xiaoxi666 Master programmers think of systems as stories to be told rather than programs to be written. 博客园 首页 新随笔 联系 订阅 管理 Java文件操作类效率对比
前言
众所周知,Java中有多种针对文件的操作类,以面向字节流和字符流可分为两大类,这里以写入为例:
面向字节流的:FileOutputStream 和 BufferedOutputStream
面向字符流的:FileWriter 和 BufferedWriter
近年来发展出New I/O ,也叫NIO,里面又包装了两个类:NewOutputStream 和 NewBufferedWriter
现在,我们建立测试程序,比较这些类写入文件的性能。
机器配置
Processor Name: Intel Core i7
Processor Speed: 2.2 GHz
Number of Processors: 1
Total Number of Cores: 4
L2 Cache (per Core): 256 KB
L3 Cache: 6 MB
Memory: 16 GB
测试程序
纵向比较:几种文件操作类向文件中写入相同行数的内容(每行内容均为“写入文件Data\n”),比较其耗费时间
横向比较:对于同一个文件操作类,比较写入不同行数内容情况下所耗费时间;本文以2的次方指数级增长行数
复制代码
1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.*;
4 import java.nio.file.Files;
5 import java.nio.file.Paths;
6
7 public class testFileIO {
8
9 public static void testDriver () throws IOException {
10 int maxlineNum = 100000001;//写入文件的最大行数
11 int startlineNum = 1;//写入文件的行数
12 int Multiplying = 2;//行数增长倍率
13
14 long begin = 0L;
15 long end = 0L;
16
17 //将时间统计写入文件Result.txt中
18 FileWriter fileWriter = new FileWriter("./Result.txt", true);
19 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
20
21 System.out.println("Test FileOutputStream begin.");
22 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {
23 begin = System.currentTimeMillis();
24 testFileOutputStream(lineNum);
25 end = System.currentTimeMillis();
26 long timeElapse_FileOutputStream = end - begin;
27 bufferedWriter.write(String.valueOf(timeElapse_FileOutputStream)+"\t");
28 }
29 System.out.println("Test FileOutputStream end.\n");
30
31 System.out.println("Test BufferedOutputStream begin.");
32 bufferedWriter.write("\n");
33 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {
34 begin = System.currentTimeMillis();
35 testBufferedOutputStream(lineNum);
36 end = System.currentTimeMillis();
37 long timeElapse_BufferedOutputStream = end - begin;
38 bufferedWriter.write(String.valueOf(timeElapse_BufferedOutputStream)+"\t");
39 }
40 System.out.println("Test BufferedOutputStream end.\n");
41
42 System.out.println("Test FileWriter begin.");
43 bufferedWriter.write("\n");
44 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {
45 begin = System.currentTimeMillis();
46 testFileWriter(lineNum);
47 end = System.currentTimeMillis();
48 long timeElapse_FileWriter = end - begin;
49 bufferedWriter.write(String.valueOf(timeElapse_FileWriter)+"\t");
50 }
51 System.out.println("Test FileWriter end.\n");
52
53 System.out.println("Test BufferedWriter begin.");
54 bufferedWriter.write("\n");
55 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {
56 begin = System.currentTimeMillis();
57 testBufferedWriter(lineNum);
58 end = System.currentTimeMillis();
59 long timeElapse_BufferedWriter = end - begin;
60 bufferedWriter.write(String.valueOf(timeElapse_BufferedWriter)+"\t");
61 }
62 System.out.println("Test BufferedWriter end.\n");
63
64 System.out.println("Test NewOutputStream begin.");
65 bufferedWriter.write("\n");
66 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {
67 begin = System.currentTimeMillis();
68 testNewOutputStream(lineNum);
69 end = System.currentTimeMillis();
70 long timeElapse_NewOutputStream = end - begin;
71 bufferedWriter.write(String.valueOf(timeElapse_NewOutputStream)+"\t");
72 }
73 System.out.println("Test NewOutputStream end.\n");
74
75 System.out.println("Test NewBufferedWriter begin.");
76 bufferedWriter.write("\n");
77 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {
78 begin = System.currentTimeMillis();
79 testNewBufferedWriter(lineNum);
80 end = System.currentTimeMillis();
81 long timeElapse_NewBufferedWriter = end - begin;
82 bufferedWriter.write(String.valueOf(timeElapse_NewBufferedWriter)+"\t");
83 }
84 System.out.println("Test NewOutputStream end.\n");
85
86 bufferedWriter.close();
87 }
88
89 /************************** I/O *****************************/
90 //面向字节
91 public static void testFileOutputStream (int lineNum) throws IOException {
92 FileOutputStream fileOutputStream = new FileOutputStream(new File("./testFileOutputStream.txt"));
93 while (--lineNum > 0) {
94 fileOutputStream.write("写入文件Data\n".getBytes());
95 }
96 fileOutputStream.close();
97 }
98
99 public static void testBufferedOutputStream (int lineNum) throws IOException {
100 FileOutputStream fileOutputStream = new FileOutputStream(new File("./testBufferedOutputStream.txt"));
101 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
102 while (--lineNum > 0) {
103 bufferedOutputStream.write("写入文件Data\n".getBytes());
104 }
105 bufferedOutputStream.close();
106 }
107
108 //面向字符
109 public static void testFileWriter (int lineNum) throws IOException {
110 FileWriter fileWriter = new FileWriter("./testFileWriter.txt");
111 while (--lineNum > 0) {
112 fileWriter.write("写入文件Data\n");
113 }
114 fileWriter.close();
115 }
116
117 public static void testBufferedWriter (int lineNum) throws IOException {
118 FileWriter fileWriter = new FileWriter("./testBufferedWriter.txt");
119 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
120 while (--lineNum > 0) {
121 bufferedWriter.write("写入文件Data\n");
122 }
123 bufferedWriter.close();
124 }
125
126
127 /************************** NIO ****************************/
128 public static void testNewOutputStream (int lineNum) throws IOException {
129 OutputStream outputStream = Files.newOutputStream(Paths.get("./testNewOutputStream.txt"));
130 while (--lineNum > 0) {
131 outputStream.write("写入文件Data\n".getBytes());
132 }
133 outputStream.close();
134 }
135
136 public static void testNewBufferedWriter (int lineNum) throws IOException {
137 BufferedWriter newBufferedReader = Files.newBufferedWriter(Paths.get("./testNewBufferedWriter.txt"));
138 while (--lineNum > 0) {
139 newBufferedReader.write("写入文件Data\n");
140 }
141 newBufferedReader.close();
142 }
143
144
145 public static void main (String[] args) throws IOException {
146 //多次测试时可清空result.txt文件
147 FileWriter fileWriter = new FileWriter("./Result.txt");
148 testDriver();
149 }
150 }
复制代码
测试结果
从上图可以看出,写入行数超过20W以上时,FileOutputStream和NewOutputStream耗费时间远远超出其他4个类。为了清晰,让我们放大其他4个类的图:
可以看出,这4个类中,BufferWriter和NewBufferedWriter所耗费时间更少,但总体差别不是很大。
让我们再来看看,写入26W行数据以下时的情况:
可以看出,在数据量较小的情况下,这4个类所耗费时间的差异并不是很大,在更小的数据量下,它们的效率几乎没有差别。
后记
从以上分析可知(注意横坐标写入行数是指数级增加的),各个类的时间复杂度大致为O(k),其中不同的类的k不同,导致了最终巨大的差异。
这里只给出了测试结果,并未分析其底层实现原理,欢迎评论区留言。
另外,我没有在其他机器测试,有兴趣的小伙伴可以将自己的测试结果发出来,共同进步^_^
附件
本次测试数据结果(若看不清,可以将浏览器字体放大,或下载到本地看)
~~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~
评论区小伙伴“ andorxor”提出:
XXXOutputStream是用来写二进制的,你把字符串转换成字节数组再写自然就慢了,主要慢在转换的过程。
因此,将程序修改,提前把字符和字节内容都准备好,再次验证。新程序如下:
View Code
结果为:
可以看出和前面的案例几乎没有差异(图就不画了)。
所以XXXOutputStream效率低的原因并不是字符串转换成字节数组,而是其本身的实现方式所致。
『注:本文来自博客园“小溪的博客”,若非声明均为原创内容,请勿用于商业用途,转载请注明出处http://www.cnblogs.com/xiaoxi666/』
https://www.cnblogs.com/xiaoxi666/p/9531893.html