Java文件拷貝方式


原創轉載請注明出處:https://www.cnblogs.com/agilestyle/p/11444284.html

 

利用java.io類庫,直接為源文件構建一個FileInputStream讀取,然后再為目標文件構建一個FileOutputStream,完成寫入工作。

 1 public static void copyFileByStream(File source, File dest) throws IOException {
 2     try (InputStream is = new FileInputStream(source);
 3          OutputStream os = new FileOutputStream(dest)) {
 4         byte[] buffer = new byte[1024];
 5         int length;
 6 
 7         while ((length = is.read(buffer)) > 0) {
 8             os.write(buffer, 0, length);
 9         }
10     }
11 }

 

利用java.nio類庫提供的transferTo或transferFrom方法實現

 1 public static void copyFileByChannel(File source, File dest) throws IOException {
 2     try (FileChannel sourceChannel = new FileInputStream(source).getChannel();
 3          FileChannel targetChannel = new FileOutputStream(dest).getChannel()) {
 4         
 5         for (long count = sourceChannel.size(); count > 0; ) {
 6             long transferred = sourceChannel.transferTo(sourceChannel.position(), count, targetChannel);
 7 
 8             sourceChannel.position(sourceChannel.position() + transferred);
 9 
10             count -= transferred;
11         }
12     }
13 }

 

Java標准類庫提供的幾種Files.copy的實現

 

對於Copy的效率,這個其實與操作系統和配置等情況相關,總體上來說,NIO transferTo/From的方式可能更快,因為它更能利用現代操作系統底層機制,避免不必要拷貝和上下文切換。

 

拷貝實現機制分析

先來理解一下,前面實現的不同拷貝方法,本質上有什么明顯的區別。

首先,需要理解用戶態空間(User Space)和內核態空間(Kernel Space),這是操作系統層面的基本概念,操作系統內核、硬件驅動等運行在內核態空間,具有相對高的特權;而用戶態空間,則是給普通應用和服務使用。可以參考:https://en.wikipedia.org/wiki/User_space

當使用輸入輸出流進行讀寫時,實際上是進行了多次上下文切換,比如應用讀取數據時,先在內核態將數據從磁盤讀取到內核緩存,再切換到用戶態將數據從內核緩存讀取到用戶緩存。

寫入操作也是類似,僅僅是步驟相反,可以參考下面這張圖。

所以,這種方式會帶來一定的額外開銷,可能會降低IO效率。

而基於NIO transferTo的實現方式,在Linux和Unix上,則會使用到零拷貝技術,數據傳輸並不需要用戶態參與,省去了上下文切換的開銷和不必要的內存拷貝,進而可能提高應用拷貝性能。注意,transferTo不僅僅是可以用在文件拷貝中,與其類似的,例如讀取磁盤文件,然后進行Socket發送,同樣可以享受這種機制帶來的性能和擴展性提高。

transferTo的傳輸過程是:

 

Reference

https://time.geekbang.org/column/article/8393


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM