日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

文件写入的6种方法,这种方法性能最好

發布時間:2024/1/23 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 文件写入的6种方法,这种方法性能最好 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在 Java 中操作文件的方法本質上只有兩種:字符流和字節流,而字節流和字符流的實現類又有很多,因此在文件寫入時我們就可以選擇各種各樣的類來實現。我們本文就來盤點一下這些方法,順便測試一下它們性能,以便為我們選出最優的寫入方法。

在正式開始之前,我們先來了解幾個基本的概念:流、字節流和字符流的定義與區別。

0.什么是流?

Java 中的“流”是一種抽象的概念,也是一種比喻,就好比水流一樣,水流是從一端流向另一端的,而在 Java 中的“水流”就是數據,數據會從一端“流向”另一端。

根據流的方向性,我們可以將流分為輸入流和輸出流,當程序需要從數據源中讀入數據的時候就會開啟一個輸入流,相反,寫出數據到某個數據源目的地的時候也會開啟一個輸出流,數據源可以是文件、內存或者網絡等。

1.什么是字節流?

字節流的基本單位為字節(Byte),一個字節通常為 8 位,它是用來處理二進制(數據)的。字節流有兩個基類:InputStream(輸入字節流)和?OutputStream(輸出字節流)。

常用字節流的繼承關系圖如下圖所示:其中?InputStream?用于讀操作,而?OutputStream?用于寫操作。

2.什么是字符流?

字符流的基本單位為 Unicode,大小為兩個字節(Byte),它通常用來處理文本數據。字符流的兩個基類:Reader(輸入字符流)和?Writer(輸出字符流)。

常用字符流的繼承關系圖如下圖所示:

3.流的分類

流可以根據不同的維度進行分類,比如可以根據流的方向進行分類,也可以根據傳輸的單位進行分類,還可以根據流的功能進行分類,比如以下幾個。

① 按流向分類

  • 輸出流:OutputStream?和?Writer?為基類。

  • 輸入流:InputStream?和?Reader?為基類。

② 根據傳輸數據單位分類

  • 字節流:OutputStream?和?InputStream?為基類。

  • 字符流:Writer?和?Reader?為基類。

③ 根據功能分類

  • 字節流:可以從或向一個特定的地方(節點)讀寫數據。

  • 處理流:是對一個已存在的流的連接和封裝,通過所封裝的流的功能調用實現數據讀寫。

PS:我們通常是以傳輸數據的單位來為流進行分類。

4.寫文件的6種方法

寫入文件的方法主要源于字符流?Writer?和輸出字節流?OutputStream?的子類,如下圖所示:

以上標注?號的類就是用來實現文件寫入的類,除此之外,在 JDK 1.7 中還提供了?Files?類用來實現對文件的各種操作,接下來我們分別來看。

方法 1:FileWriter

FileWriter?屬于「字符流」體系中的一員,也是文件寫入的基礎類,它包含 5 個構造函數,可以傳遞一個具體的文件位置,或者?File?對象,第二參數表示是否要追加文件,默認值為?false?表示重寫文件內容,而非追加文件內容(關于如何追加文件,我們后面會講)。

FileWriter?類的實現如下:

/***?方法 1:使用 FileWriter 寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/ public?static?void?fileWriterMethod(String?filepath,?String?content)?throws?IOException?{try?(FileWriter?fileWriter?=?new?FileWriter(filepath))?{fileWriter.append(content);} }

只需要傳入具體的文件路徑和待寫入的內容即可,調用代碼如下:

public?static?void?main(String[]?args)?{fileWriterMethod("/Users/mac/Downloads/io_test/write1.txt",?"哈嘍,Java中文社群."); }

然后我們打開寫入的文件,實現結果如下:

關于資源釋放的問題:在 JDK 7 以上的版本,我們只需要使用 try-with-resource 的方式就可以實現資源的釋放,就比如使用 try (FileWriter fileWriter = new FileWriter(filepath)) {...} 就可以實現 FileWriter 資源的自動釋放。

方法 2:BufferedWriter

BufferedWriter?也屬于字符流體系的一員,與?FileWriter?不同的是?BufferedWriter?自帶緩沖區,因此它寫入文件的性能更高(下文會對二者進行測試)。

小知識點:緩沖區

緩沖區又稱為緩存,它是內存空間的一部分。也就是說,在內存空間中預留了一定的存儲空間,這些存儲空間用來緩沖輸入或輸出的數據,這部分預留的空間就叫做緩沖區。

緩沖區的優勢以文件流的寫入為例,如果我們不使用緩沖區,那么每次寫操作 CPU 都會和低速存儲設備也就是磁盤進行交互,那么整個寫入文件的速度就會受制于低速的存儲設備(磁盤)。但如果使用緩沖區的話,每次寫操作會先將數據保存在高速緩沖區內存上,當緩沖區的數據到達某個閾值之后,再將文件一次性寫入到磁盤上。因為內存的寫入速度遠遠大于磁盤的寫入速度,所以當有了緩沖區之后,文件的寫入速度就被大大提升了。

了解了緩存區的優點之后,咱們回到本文的主題,接下來我們用?BufferedWriter?來文件的寫入,實現代碼如下:

/***?方法 2:使用 BufferedWriter 寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/ public?static?void?bufferedWriterMethod(String?filepath,?String?content)?throws?IOException?{try?(BufferedWriter?bufferedWriter?=?new?BufferedWriter(new?FileWriter(filepath)))?{bufferedWriter.write(content);} }

調用代碼和方法 1 類似,這里就不再贅述了。

方法 3:PrintWriter

PrintWriter?也屬于字符流體系中的一員,它雖然叫“字符打印流”,但使用它也可以實現文件的寫入,實現代碼如下:

/***?方法 3:使用 PrintWriter 寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/ public?static?void?printWriterMethod(String?filepath,?String?content)?throws?IOException?{try?(PrintWriter?printWriter?=?new?PrintWriter(new?FileWriter(filepath)))?{printWriter.print(content);} }

從上述代碼可以看出,無論是?PrintWriter?還是?BufferedWriter?都必須基于?FileWriter?類來完成調用。

方法 4:FileOutputStream

上面 3 個示例是關于字符流寫入文件的一些操作,而接下來我們將使用字節流來完成文件寫入。我們將使用?String?自帶的?getBytes()?方法先將字符串轉換成二進制文件,然后再進行文件寫入,它的實現代碼如下:

/***?方法 4:使用 FileOutputStream 寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/ public?static?void?fileOutputStreamMethod(String?filepath,?String?content)?throws?IOException?{try?(FileOutputStream?fileOutputStream?=?new?FileOutputStream(filepath))?{byte[]?bytes?=?content.getBytes();fileOutputStream.write(bytes);} }

方法 5:BufferedOutputStream

BufferedOutputStream?屬于字節流體系中的一員,與?FileOutputStream?不同的是,它自帶了緩沖區的功能,因此性能更好,它的實現代碼如下:

/***?方法 5:使用 BufferedOutputStream 寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/ public?static?void?bufferedOutputStreamMethod(String?filepath,?String?content)?throws?IOException?{try?(BufferedOutputStream?bufferedOutputStream?=?new?BufferedOutputStream(new?FileOutputStream(filepath)))?{bufferedOutputStream.write(content.getBytes());} }

方法 6:Files

接下來的操作方法和之前的代碼都不同,接下來咱們就使用 JDK 7 中提供的一個新的文件操作類?Files?來實現文件的寫入。

Files?類是 JDK 7 添加的新的操作文件的類,它提供了提供了大量處理文件的方法,例如文件復制、讀取、寫入,獲取文件屬性、快捷遍歷文件目錄等,這些方法極大的方便了文件的操作,它的實現代碼如下:

/***?方法 6:使用 Files 寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/ public?static?void?filesTest(String?filepath,?String?content)?throws?IOException?{Files.write(Paths.get(filepath),?content.getBytes()); }

以上這些方法都可以實現文件的寫入,那哪一種方法性能更高呢?接下來我們來測試一下。

5.性能測試

我們先來構建一個比較大的字符串,然后分別用以上 6 種方法來測試文件寫入的速度,最后再把結果打印出來,測試代碼如下:

import?java.io.*; import?java.nio.file.Files; import?java.nio.file.Paths;public?class?WriteExample?{public?static?void?main(String[]?args)?throws?IOException?{//?構建寫入內容StringBuilder?stringBuilder?=?new?StringBuilder();for?(int?i?=?0;?i?<?1000000;?i++)?{stringBuilder.append("ABCDEFGHIGKLMNOPQRSEUVWXYZ");}//?寫入內容final?String?content?=?stringBuilder.toString();//?存放文件的目錄final?String?filepath1?=?"/Users/mac/Downloads/io_test/write1.txt";final?String?filepath2?=?"/Users/mac/Downloads/io_test/write2.txt";final?String?filepath3?=?"/Users/mac/Downloads/io_test/write3.txt";final?String?filepath4?=?"/Users/mac/Downloads/io_test/write4.txt";final?String?filepath5?=?"/Users/mac/Downloads/io_test/write5.txt";final?String?filepath6?=?"/Users/mac/Downloads/io_test/write6.txt";//?方法一:使用?FileWriter?寫文件long?stime1?=?System.currentTimeMillis();fileWriterTest(filepath1,?content);long?etime1?=?System.currentTimeMillis();System.out.println("FileWriter?寫入用時:"?+?(etime1?-?stime1));//?方法二:使用?BufferedWriter?寫文件long?stime2?=?System.currentTimeMillis();bufferedWriterTest(filepath2,?content);long?etime2?=?System.currentTimeMillis();System.out.println("BufferedWriter?寫入用時:"?+?(etime2?-?stime2));//?方法三:使用?PrintWriter?寫文件long?stime3?=?System.currentTimeMillis();printWriterTest(filepath3,?content);long?etime3?=?System.currentTimeMillis();System.out.println("PrintWriterTest?寫入用時:"?+?(etime3?-?stime3));//?方法四:使用?FileOutputStream??寫文件long?stime4?=?System.currentTimeMillis();fileOutputStreamTest(filepath4,?content);long?etime4?=?System.currentTimeMillis();System.out.println("FileOutputStream?寫入用時:"?+?(etime4?-?stime4));//?方法五:使用?BufferedOutputStream?寫文件long?stime5?=?System.currentTimeMillis();bufferedOutputStreamTest(filepath5,?content);long?etime5?=?System.currentTimeMillis();System.out.println("BufferedOutputStream?寫入用時:"?+?(etime5?-?stime5));//?方法六:使用?Files?寫文件long?stime6?=?System.currentTimeMillis();filesTest(filepath6,?content);long?etime6?=?System.currentTimeMillis();System.out.println("Files?寫入用時:"?+?(etime6?-?stime6));}/***?方法六:使用?Files?寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/private?static?void?filesTest(String?filepath,?String?content)?throws?IOException?{Files.write(Paths.get(filepath),?content.getBytes());}/***?方法五:使用?BufferedOutputStream?寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/private?static?void?bufferedOutputStreamTest(String?filepath,?String?content)?throws?IOException?{try?(BufferedOutputStream?bufferedOutputStream?=?new?BufferedOutputStream(new?FileOutputStream(filepath)))?{bufferedOutputStream.write(content.getBytes());}}/***?方法四:使用?FileOutputStream??寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/private?static?void?fileOutputStreamTest(String?filepath,?String?content)?throws?IOException?{try?(FileOutputStream?fileOutputStream?=?new?FileOutputStream(filepath))?{byte[]?bytes?=?content.getBytes();fileOutputStream.write(bytes);}}/***?方法三:使用?PrintWriter?寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/private?static?void?printWriterTest(String?filepath,?String?content)?throws?IOException?{try?(PrintWriter?printWriter?=?new?PrintWriter(new?FileWriter(filepath)))?{printWriter.print(content);}}/***?方法二:使用?BufferedWriter?寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/private?static?void?bufferedWriterTest(String?filepath,?String?content)?throws?IOException?{try?(BufferedWriter?bufferedWriter?=?new?BufferedWriter(new?FileWriter(filepath)))?{bufferedWriter.write(content);}}/***?方法一:使用?FileWriter?寫文件*?@param?filepath?文件目錄*?@param?content??待寫入內容*?@throws?IOException*/private?static?void?fileWriterTest(String?filepath,?String?content)?throws?IOException?{try?(FileWriter?fileWriter?=?new?FileWriter(filepath))?{fileWriter.append(content);}} }

在查看結果之前,我們先去對應的文件夾看看寫入的文件是否正常,如下圖所示:

從上述結果可以看出,每種方法都正常寫入了 26 MB 的數據,它們最終執行的結果如下圖所示:

從以上結果可以看出,字符流的操作速度最快,這是因為我們本次測試的代碼操作的是字符串,所以在使用字節流時,需要先將字符串轉換為字節流,因此在執行效率上不占優勢。

從上述結果可以看出,性能最好的是帶有緩沖區的字符串寫入流?BufferedWriter,性能最慢的是?Files。

PS:以上的測試結果只是針對字符串的操作場景有效,如果操作的是二進制的文件,那么就應該使用帶緩沖區的字節流 BufferedOutputStream。

6.擴展知識:內容追加

以上代碼會對文件進行重寫,如果只想在原有的基礎上追加內容,就需要在創建寫入流的時候多設置一個?append?的參數為?true,比如如果我們使用?FileWriter?來實現文件的追加的話,實現代碼是這樣的:

public?static?void?fileWriterMethod(String?filepath,?String?content)?throws?IOException?{//?第二個?append?的參數傳遞一個?true?=?追加文件的意思try?(FileWriter?fileWriter?=?new?FileWriter(filepath,?true))?{fileWriter.append(content);} }

如果使用的是?BufferedWriter?或?PrintWriter,也是需要在構建?new FileWriter?類時多設置一個?append?的參數為?true,實現代碼如下:

try?(BufferedWriter?bufferedWriter?=?new?BufferedWriter(new?FileWriter(filepath,?true)))?{bufferedWriter.write(content); }

相比來說?Files?類要想實現文件的追加寫法更加特殊一些,它需要在調用?write?方法時多傳一個?StandardOpenOption.APPEND?的參數,它的實現代碼如下:

Files.write(Paths.get(filepath),?content.getBytes(),?StandardOpenOption.APPEND);

7.總結

本文我們展示了 6 種寫入文件的方法,這 6 種方法總共分為 3 類:字符流寫入、字節流寫入和?Files?類寫入。其中操作最便利的是?Files?類,但它的性能不怎么好。如果對性能有要求就推薦使用帶有緩存區的流來完成操作,如?BufferedWriter?或?BufferedOutputStream。如果寫入的內容是字符串的話,那么推薦使用?BufferedWriter,如果寫入的內容是二進制文件的話就推薦使用?BufferedOutputStream。

參考 & 鳴謝

https://www.cnblogs.com/absfree/p/5415092.html

- END -

總結

以上是生活随笔為你收集整理的文件写入的6种方法,这种方法性能最好的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。