前言
眾所周知,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是用來寫二進制的,你把字符串轉換成字節數組再寫自然就慢了,主要慢在轉換的過程。
因此,將程序修改,提前把字符和字節內容都准備好,再次驗證。新程序如下:

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 10 public static void testDriver () throws IOException { 11 int maxlineNum = 100000001;//寫入文件的最大行數 12 int startlineNum = 1;//寫入文件的行數 13 int Multiplying = 2;//行數增長倍率 14 15 String contentChars = "寫入文件Data\n";//每行的內容(字符流) 16 byte[] contentBytes = "寫入文件Data\n".getBytes();//每行的內容(字節流) 17 18 long begin = 0L; 19 long end = 0L; 20 21 //將時間統計寫入文件Result.txt中 22 FileWriter fileWriter = new FileWriter("./Result.txt", true); 23 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 24 25 System.out.println("Test FileOutputStream begin."); 26 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 27 begin = System.currentTimeMillis(); 28 testFileOutputStream(lineNum,contentBytes); 29 end = System.currentTimeMillis(); 30 long timeElapse_FileOutputStream = end - begin; 31 bufferedWriter.write(String.valueOf(timeElapse_FileOutputStream)+"\t"); 32 } 33 System.out.println("Test FileOutputStream end.\n"); 34 35 System.out.println("Test BufferedOutputStream begin."); 36 bufferedWriter.write("\n"); 37 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 38 begin = System.currentTimeMillis(); 39 testBufferedOutputStream(lineNum,contentBytes); 40 end = System.currentTimeMillis(); 41 long timeElapse_BufferedOutputStream = end - begin; 42 bufferedWriter.write(String.valueOf(timeElapse_BufferedOutputStream)+"\t"); 43 } 44 System.out.println("Test BufferedOutputStream end.\n"); 45 46 System.out.println("Test FileWriter begin."); 47 bufferedWriter.write("\n"); 48 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 49 begin = System.currentTimeMillis(); 50 testFileWriter(lineNum,contentChars); 51 end = System.currentTimeMillis(); 52 long timeElapse_FileWriter = end - begin; 53 bufferedWriter.write(String.valueOf(timeElapse_FileWriter)+"\t"); 54 } 55 System.out.println("Test FileWriter end.\n"); 56 57 System.out.println("Test BufferedWriter begin."); 58 bufferedWriter.write("\n"); 59 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 60 begin = System.currentTimeMillis(); 61 testBufferedWriter(lineNum,contentChars); 62 end = System.currentTimeMillis(); 63 long timeElapse_BufferedWriter = end - begin; 64 bufferedWriter.write(String.valueOf(timeElapse_BufferedWriter)+"\t"); 65 } 66 System.out.println("Test BufferedWriter end.\n"); 67 68 System.out.println("Test NewOutputStream begin."); 69 bufferedWriter.write("\n"); 70 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 71 begin = System.currentTimeMillis(); 72 testNewOutputStream(lineNum,contentBytes); 73 end = System.currentTimeMillis(); 74 long timeElapse_NewOutputStream = end - begin; 75 bufferedWriter.write(String.valueOf(timeElapse_NewOutputStream)+"\t"); 76 } 77 System.out.println("Test NewOutputStream end.\n"); 78 79 System.out.println("Test NewBufferedWriter begin."); 80 bufferedWriter.write("\n"); 81 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 82 begin = System.currentTimeMillis(); 83 testNewBufferedWriter(lineNum,contentChars); 84 end = System.currentTimeMillis(); 85 long timeElapse_NewBufferedWriter = end - begin; 86 bufferedWriter.write(String.valueOf(timeElapse_NewBufferedWriter)+"\t"); 87 } 88 System.out.println("Test NewOutputStream end.\n"); 89 90 bufferedWriter.close(); 91 } 92 93 /************************** I/O *****************************/ 94 //面向字節 95 public static void testFileOutputStream (int lineNum, byte[] content) throws IOException { 96 FileOutputStream fileOutputStream = new FileOutputStream(new File("./testFileOutputStream.txt")); 97 while (--lineNum > 0) { 98 fileOutputStream.write(content); 99 } 100 fileOutputStream.close(); 101 } 102 103 public static void testBufferedOutputStream (int lineNum, byte[] content) throws IOException { 104 FileOutputStream fileOutputStream = new FileOutputStream(new File("./testBufferedOutputStream.txt")); 105 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); 106 while (--lineNum > 0) { 107 bufferedOutputStream.write(content); 108 } 109 bufferedOutputStream.close(); 110 } 111 112 //面向字符 113 public static void testFileWriter (int lineNum, String content) throws IOException { 114 FileWriter fileWriter = new FileWriter("./testFileWriter.txt"); 115 while (--lineNum > 0) { 116 fileWriter.write(content); 117 } 118 fileWriter.close(); 119 } 120 121 public static void testBufferedWriter (int lineNum, String content) throws IOException { 122 FileWriter fileWriter = new FileWriter("./testBufferedWriter.txt"); 123 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 124 while (--lineNum > 0) { 125 bufferedWriter.write(content); 126 } 127 bufferedWriter.close(); 128 } 129 130 131 /************************** NIO ****************************/ 132 public static void testNewOutputStream (int lineNum, byte[] content) throws IOException { 133 OutputStream outputStream = Files.newOutputStream(Paths.get("./testNewOutputStream.txt")); 134 while (--lineNum > 0) { 135 outputStream.write(content); 136 } 137 outputStream.close(); 138 } 139 140 public static void testNewBufferedWriter (int lineNum,String content) throws IOException { 141 BufferedWriter newBufferedReader = Files.newBufferedWriter(Paths.get("./testNewBufferedWriter.txt")); 142 while (--lineNum > 0) { 143 newBufferedReader.write(content); 144 } 145 newBufferedReader.close(); 146 } 147 148 149 public static void main (String[] args) throws IOException { 150 //多次測試時可清空result.txt文件 151 FileWriter fileWriter = new FileWriter("./Result.txt"); 152 testDriver(); 153 } 154 }
結果為:
可以看出和前面的案例幾乎沒有差異(圖就不畫了)。
所以XXXOutputStream效率低的原因並不是字符串轉換成字節數組,而是其本身的實現方式所致。
~~~~~~~~~~~~~~~~~~~~~分割線:底層實現原理淺談~~~~~~~~~~~~~~~~~~~~~~~
其實,計算機中都是針對字節操作的(即字符都要經過編碼轉換為字節),那么問題來了,FileOutputStream為什么比FileWriter(FileWriter內部還有FileOutputStream轉換操作,具體看源碼)還要慢呢?且慢,讓我們把寫入文件的數據改一下:

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 10 public static void testDriver () throws IOException { 11 int maxlineNum = 500001;//寫入文件的最大行數 12 int startlineNum = 1;//寫入文件的行數 13 int Multiplying = 2;//行數增長倍率 14 15 String baseContent = "背景\n" + 16 "考慮以下場景:\n" + 17 "\n" + 18 "InfoTable(信息表):\n" + 19 "\n" + 20 "Name\tGender\tAge\tScore\n" + 21 "張三\t男\t21\t90\n" + 22 "李四\t女\t20\t87\n" + 23 "王五\t男\t22\t92\n" + 24 "趙六\t女\t19\t94\n" + 25 "孫七\t女\t23\t88\n" + 26 "周八\t男\t20\t91\n" + 27 "StatusTable(狀態表,指是否有在考試之前復習):\n" + 28 "\n" + 29 "Name\thasReview\n" + 30 "張三\t是\n" + 31 "李四\t否\n" + 32 "王五\t是\n" + 33 "趙六\t是\n" + 34 "孫七\t否\n" + 35 "周八\t是\n" + 36 "現在,我想知道所有復習過的學生的成績,可以利用mysql中的子查詢來實現:\n" + 37 "\n" + 38 "SELECT Score \n" + 39 "FROM InfoTable \n" + 40 "WHERE Name in (SELECT Name \n" + 41 " FROM StatusTable \n" + 42 " WHERE hasReview = '是');\n" + 43 "這種方式非常方便,我們只要把查詢條件寫出來,剩下的操作都由mysql來處理。而在實際場景中,為了減少底層耦合,我們一般不通過mysql中的子查詢方式聯表查詢,而是先執行子查詢得到結果集,再以結果集作為條件執行外層查詢。通常情況下,子查詢和外層查詢由上層的不同服務執行,這樣就在一定程度上達到了底層數據庫解耦的目的。注意這種實現方式將mysql內部的一部分復雜操作拋給了我們。這時,Mybatis中的foreach標簽就有了用武之地。\n" + 44 "\n" + 45 "Mybatis 中foreach標簽的用法\n" + 46 "還以剛才的例子來說,先執行子查詢\n" + 47 "\n" + 48 "SELECT Name FROM StatusTable WHERE hasReview = '是'\n" + 49 "再執行外層查詢,就是\n" + 50 "\n" + 51 "SELECT Score \n" + 52 "FROM InfoTable \n" + 53 "WHERE Name in ('張三' , '王五', '趙六', '周八');\n" + 54 "也就是一個批量查詢操作,將其抽象一下(假設有三個條件):\n" + 55 "\n" + 56 "SELECT * \n" + 57 "FROM <tableName> \n" + 58 "WHERE <ColumnName> IN (<case1>,<case2>,<case3>)\n" + 59 "實際情況中,case可能遠不止3個,這時可以在XXXMapper.xml文件中利用Mybatis中的foreach編寫sql語句:\n" + 60 "\n" + 61 "SELECT * \n" + 62 "FROM <tableName> \n" + 63 "WHERE <ColumnName> IN \n" + 64 "<foreach collection=\"list\" index=\"index\" item=\"item\" open=\"(\" separator=\",\" close=\")\">\n" + 65 " #{item}\n" + 66 "</foreach>\n" + 67 "就可以實現相同的效果了。\n" + 68 "\n" + 69 "那么問題來了,foreach標簽中各種參數是什么含義呢?\n" + 70 "\n" + 71 "collection\n" + 72 "如果傳入的是單參數且參數類型是一個List的時候,collection屬性值為list\n" + 73 "如果傳入的是單參數且參數類型是一個array數組的時候,collection的屬性值為array\n" + 74 "如果傳入的參數是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數也可以封裝成map,實際上如果你在傳入參數的時候,在breast里面也是會把它封裝成一個Map的,map的key就是參數名,所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map里面的key\n" + 75 "index 集合迭代位置\n" + 76 "item 集合中的每一個元素別名\n" + 77 "open 開始符號,例如這里的(,就對應於IN (<case1>,<case2>,<case3>)中IN后面的第一個(\n" + 78 "separator 分隔符,例如這里的,,就對應於IN (<case1>,<case2>,<case3>)中的,\n" + 79 "close 結束符號,例如這里的),就對應於IN (<case1>,<case2>,<case3>)中<case3>后面的)\n" + 80 "參考\n"; 81 82 String contentChars = baseContent;//每行的內容(字符流) 83 byte[] contentBytes = baseContent.getBytes();//每行的內容(字節流) 84 85 long begin = 0L; 86 long end = 0L; 87 88 //將時間統計寫入文件Result.txt中 89 FileWriter fileWriter = new FileWriter("./Result.txt", true); 90 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 91 92 System.out.println("Test FileOutputStream begin."); 93 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 94 begin = System.currentTimeMillis(); 95 testFileOutputStream(lineNum,contentBytes); 96 end = System.currentTimeMillis(); 97 long timeElapse_FileOutputStream = end - begin; 98 bufferedWriter.write(String.valueOf(timeElapse_FileOutputStream)+"\t"); 99 } 100 System.out.println("Test FileOutputStream end.\n"); 101 102 System.out.println("Test BufferedOutputStream begin."); 103 bufferedWriter.write("\n"); 104 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 105 begin = System.currentTimeMillis(); 106 testBufferedOutputStream(lineNum,contentBytes); 107 end = System.currentTimeMillis(); 108 long timeElapse_BufferedOutputStream = end - begin; 109 bufferedWriter.write(String.valueOf(timeElapse_BufferedOutputStream)+"\t"); 110 } 111 System.out.println("Test BufferedOutputStream end.\n"); 112 113 System.out.println("Test FileWriter begin."); 114 bufferedWriter.write("\n"); 115 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 116 begin = System.currentTimeMillis(); 117 testFileWriter(lineNum,contentChars); 118 end = System.currentTimeMillis(); 119 long timeElapse_FileWriter = end - begin; 120 bufferedWriter.write(String.valueOf(timeElapse_FileWriter)+"\t"); 121 } 122 System.out.println("Test FileWriter end.\n"); 123 124 System.out.println("Test BufferedWriter begin."); 125 bufferedWriter.write("\n"); 126 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 127 begin = System.currentTimeMillis(); 128 testBufferedWriter(lineNum,contentChars); 129 end = System.currentTimeMillis(); 130 long timeElapse_BufferedWriter = end - begin; 131 bufferedWriter.write(String.valueOf(timeElapse_BufferedWriter)+"\t"); 132 } 133 System.out.println("Test BufferedWriter end.\n"); 134 135 System.out.println("Test NewOutputStream begin."); 136 bufferedWriter.write("\n"); 137 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 138 begin = System.currentTimeMillis(); 139 testNewOutputStream(lineNum,contentBytes); 140 end = System.currentTimeMillis(); 141 long timeElapse_NewOutputStream = end - begin; 142 bufferedWriter.write(String.valueOf(timeElapse_NewOutputStream)+"\t"); 143 } 144 System.out.println("Test NewOutputStream end.\n"); 145 146 System.out.println("Test NewBufferedWriter begin."); 147 bufferedWriter.write("\n"); 148 for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) { 149 begin = System.currentTimeMillis(); 150 testNewBufferedWriter(lineNum,contentChars); 151 end = System.currentTimeMillis(); 152 long timeElapse_NewBufferedWriter = end - begin; 153 bufferedWriter.write(String.valueOf(timeElapse_NewBufferedWriter)+"\t"); 154 } 155 System.out.println("Test NewOutputStream end.\n"); 156 157 bufferedWriter.close(); 158 } 159 160 /************************** I/O *****************************/ 161 //面向字節 162 public static void testFileOutputStream (int lineNum, byte[] content) throws IOException { 163 FileOutputStream fileOutputStream = new FileOutputStream(new File("./testFileOutputStream.txt")); 164 while (--lineNum > 0) { 165 fileOutputStream.write(content); 166 } 167 fileOutputStream.close(); 168 } 169 170 public static void testBufferedOutputStream (int lineNum, byte[] content) throws IOException { 171 FileOutputStream fileOutputStream = new FileOutputStream(new File("./testBufferedOutputStream.txt")); 172 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); 173 while (--lineNum > 0) { 174 bufferedOutputStream.write(content); 175 } 176 bufferedOutputStream.close(); 177 } 178 179 //面向字符 180 public static void testFileWriter (int lineNum, String content) throws IOException { 181 FileWriter fileWriter = new FileWriter("./testFileWriter.txt"); 182 while (--lineNum > 0) { 183 fileWriter.write(content); 184 } 185 fileWriter.close(); 186 } 187 188 public static void testBufferedWriter (int lineNum, String content) throws IOException { 189 FileWriter fileWriter = new FileWriter("./testBufferedWriter.txt"); 190 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 191 while (--lineNum > 0) { 192 bufferedWriter.write(content); 193 } 194 bufferedWriter.close(); 195 } 196 197 198 /************************** NIO ****************************/ 199 public static void testNewOutputStream (int lineNum, byte[] content) throws IOException { 200 OutputStream outputStream = Files.newOutputStream(Paths.get("./testNewOutputStream.txt")); 201 while (--lineNum > 0) { 202 outputStream.write(content); 203 } 204 outputStream.close(); 205 } 206 207 public static void testNewBufferedWriter (int lineNum,String content) throws IOException { 208 BufferedWriter newBufferedReader = Files.newBufferedWriter(Paths.get("./testNewBufferedWriter.txt")); 209 while (--lineNum > 0) { 210 newBufferedReader.write(content); 211 } 212 newBufferedReader.close(); 213 } 214 215 216 public static void main (String[] args) throws IOException { 217 //多次測試時可清空result.txt文件 218 FileWriter fileWriter = new FileWriter("./Result.txt"); 219 testDriver(); 220 } 221 }
這次數據量就很大了,結果也就變了:
所以,數據量很小的情況下,字符到字節的編碼操作帶來的性能降低幾乎忽略不計;而數據量很大的時候,編碼耗費的時間就很可觀了。至於為什么在小數據量的情況下FileWriter快很多,目前我認為是一次操作兩個字節所致(有了緩存之后就差不多了)。