FileChannel原理


 官方對Channel的解釋

 

(一個用於輸入/輸出操作的連接。通道表示對實體的開放連接,如硬件設備、文件、網絡套接字或能夠執行一個或多個不同的輸入/輸出操作的程序組件,例如讀取或寫入。)

 

Thanking In Java中的描述

 

Channel是對I/O操作的封裝。

FileChannel配合着ByteBuffer,將讀寫的數據緩存到內存中,然后以批量/緩存的方式read/write,省去了非批量操作時的重復中間操作,操縱大文件時可以顯著提高效率(和Stream以byte數組方式有什么區別?經過測試,效率上幾乎無區別)。

不過對於運行在容器中的應用需要考慮GC,而ByteBuffer可以使用直接內存(系統內存)(allocateDirect),使用后無需jvm回收。

ByteBuffer還有一個子類MappedByteBuffer可以直接將文件映射到操作系統的虛擬內存,讀寫文件速度會更快,參考https://www.cnblogs.com/lyftest/p/6564282.html。

 

FileChannel和Stream的使用方式和效率對比代碼

  1 import java.io.*;
  2 import java.nio.ByteBuffer;
  3 import java.nio.channels.FileChannel;
  4 import java.time.Duration;
  5 import java.time.Instant;
  6 
  7 public class FileChannelTest {
  8 
  9     public static void main(String[] args) {
 10         // 4GB的數據
 11         File sourceFile = new File("d://dd.iso");
 12         File targetFile = new File("d://ee.iso");
 13         targetFile.deleteOnExit();
 14         try {
 15             targetFile.createNewFile();
 16         } catch (IOException e) {
 17             e.printStackTrace();
 18         }
 19 
 20         // stream方式
 21         FileChannelTest.copyFileByStream(sourceFile, targetFile);
 22 
 23         // channel方式
 24 //        FileChannelTest.copyFileByFileChannel(sourceFile, targetFile);
 25     }
 26 
 27     /**
 28      * channel方式
 29      *
 30      * @param sourceFile
 31      * @param targetFile
 32      */
 33     public static void copyFileByFileChannel(File sourceFile, File targetFile) {
 34         Instant begin = Instant.now();
 35 
 36         RandomAccessFile randomAccessSourceFile;
 37         RandomAccessFile randomAccessTargetFile;
 38         try {
 39             // 構造RandomAccessFile,用於獲取FileChannel
 40             randomAccessSourceFile = new RandomAccessFile(sourceFile, "r");
 41             randomAccessTargetFile = new RandomAccessFile(targetFile, "rw");
 42         } catch (FileNotFoundException e) {
 43             e.printStackTrace();
 44             return;
 45         }
 46 
 47         FileChannel sourceFileChannel = randomAccessSourceFile.getChannel();
 48         FileChannel targetFileChannel = randomAccessTargetFile.getChannel();
 49 
 50         // 分配1MB的緩存空間
 51         ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024);
 52         try {
 53             while (sourceFileChannel.read(byteBuffer) != -1) {
 54                 byteBuffer.flip();
 55                 targetFileChannel.write(byteBuffer);
 56                 byteBuffer.clear();
 57             }
 58         } catch (IOException e) {
 59             e.printStackTrace();
 60         } finally {
 61             try {
 62                 sourceFileChannel.close();
 63             } catch (IOException e) {
 64                 e.printStackTrace();
 65             }
 66             try {
 67                 targetFileChannel.close();
 68             } catch (IOException e) {
 69                 e.printStackTrace();
 70             }
 71         }
 72 
 73         System.out.println("total spent " + Duration.between(begin, Instant.now()).toMillis());
 74     }
 75 
 76     /**
 77      * stream方式
 78      *
 79      * @param sourceFile
 80      * @param targetFile
 81      */
 82     public static void copyFileByStream(File sourceFile, File targetFile) {
 83         Instant begin = Instant.now();
 84 
 85         FileInputStream fis;
 86         FileOutputStream fos;
 87         try {
 88             fis = new FileInputStream(sourceFile);
 89             fos = new FileOutputStream(targetFile);
 90         } catch (FileNotFoundException e) {
 91             e.printStackTrace();
 92             return;
 93         }
 94         // 使用byte數組讀取方式,緩存1MB數據
 95         byte[] readed = new byte[1024 * 1024];
 96         try {
 97             while (fis.read(readed) != -1) {
 98                 fos.write(readed);
 99             }
100         } catch (IOException e) {
101             e.printStackTrace();
102         } finally {
103             try {
104                 fos.close();
105             } catch (IOException e) {
106                 e.printStackTrace();
107             }
108             try {
109                 fis.close();
110             } catch (IOException e) {
111                 e.printStackTrace();
112             }
113         }
114 
115         System.out.println("total spent " + Duration.between(begin, Instant.now()).toMillis());
116     }
117 }

 


免責聲明!

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



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