一、FileChannel的優勢
FileChannel是Java NIO庫中的一個重要類,作為Java中File I/O讀寫的另一種方式,相較於傳統的IO方式,FileChannel具有以下優勢:
1. 更快的I/O操作,只適用於間隔地讀或寫一個大容量的數據塊;
2. 可以直接操作直接內存映射文件,使用堆外內存讀寫操作;
3. 支持非阻塞I/O,可以使用單獨的線程讀寫文件,FileChannel中的data與NIO庫的selector結合可以實現同步非阻塞IO;
4. 支持多個並發訪問;
5. 可以鎖定文件的某個區域以進行獨佔訪問;
6. 可以將兩個或多個FileChannel中的數據直接傳輸,實現零拷貝,加快文件的讀取和寫入速度。
二、FileChannel讀取文件
FileChannel的read()方法提供了多種方式讀取文件。最常用的是使用ByteBuffer緩衝區進行讀取:
try(RandomAccessFile file = new RandomAccessFile("test.txt", "rw"); FileChannel channel = file.getChannel()){ ByteBuffer buffer = ByteBuffer.allocate(1024); while (channel.read(buffer) != -1){ buffer.flip(); while (buffer.hasRemaining()){ System.out.print((char) buffer.get()); } buffer.clear(); } } catch (IOException e) { e.printStackTrace(); }
三、FileChannel寫文件
FileChannel的write()方法提供了多種方式寫入數據到文件。最常用的是使用ByteBuffer緩衝區進行寫入:
try(RandomAccessFile file = new RandomAccessFile("test.txt", "rw"); FileChannel channel = file.getChannel()){ ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.put("Test String".getBytes()); buffer.flip(); while (buffer.hasRemaining()){ channel.write(buffer); } } catch (IOException e) { e.printStackTrace(); }
四、FileChannel寫入文件
FileChannel提供了map()方法將一個文件區域直接映射到內存中,讀寫操作直接在內存中進行:
try(RandomAccessFile file = new RandomAccessFile("test.txt", "rw"); FileChannel channel = file.getChannel()){ MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024); buffer.put("Test String".getBytes()); } catch (IOException e) { e.printStackTrace(); }
五、FileChannel線程安全
FileChannel是線程安全的,因為FileChannel實例方法中的狀態是由操作系統中的文件對象來維護的。即使有多個線程同時對同一個FileChannel操作,操作系統也會協作來保證正確的順序和正確的結果。
六、FileChannel可以實現數據零拷貝
FileChannel提供的transferTo()方法和transferFrom()方法可以非常高效地傳輸數據,實現數據的零拷貝。
try(RandomAccessFile file = new RandomAccessFile("src.txt", "rw"); FileChannel srcChannel = file.getChannel(); RandomAccessFile outputFile = new RandomAccessFile("dest.txt", "rw"); FileChannel outputChannel = outputFile.getChannel() ) { long position = 0; long count = srcChannel.size(); srcChannel.transferTo(position, count, outputChannel); } catch (IOException e) { e.printStackTrace(); }
七、FileChannel.write的寫入速度
FileChannel通過ByteBuffer進行寫入操作的性能非常高,一般會比傳統的IO方式的性能快很多。下面我們來比較一下FileChannel和傳統的IO流的寫入速度:
try(FileOutputStream fos = new FileOutputStream("test.txt")){ FileChannel fileChannel = fos.getChannel(); long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { ByteBuffer buffer = ByteBuffer.allocate(64); buffer.put("123456789012345678901234567890123456789012345678901234567890123\n".getBytes()); buffer.flip(); fileChannel.write(buffer); } System.out.println("FileChannel Time:" + (System.currentTimeMillis() - start) + " ms"); } catch (IOException e) { e.printStackTrace(); } try(FileOutputStream fos = new FileOutputStream("test.txt")){ long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { fos.write("123456789012345678901234567890123456789012345678901234567890123\n".getBytes()); } System.out.println("FileOutputStream Time:" + (System.currentTimeMillis() - start) + " ms"); } catch (IOException e) { e.printStackTrace(); }
八、FileChannel.map
FileChannel提供的map方法可以將文件映射為一個ByteBuffer。通過修改ByteBuffer中的數據會修改文件的內容:
try(RandomAccessFile file = new RandomAccessFile("test.txt", "rw"); FileChannel channel = file.getChannel()){ MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, channel.size()); buffer.put(0, (byte) 'H'); buffer.put(1, (byte) 'e'); buffer.put(2, (byte) 'l'); buffer.put(3, (byte) 'l'); buffer.put(4, (byte) 'o'); } catch (IOException e) { e.printStackTrace(); }
九、FileChannel.transferTo
FileChannel提供的transferTo方法將數據從源通道傳輸到目標通道,實現了零拷貝,速度比傳統的IO流快很多:
try(RandomAccessFile file = new RandomAccessFile("src.txt", "rw"); FileChannel srcChannel = file.getChannel(); RandomAccessFile outputFile = new RandomAccessFile("dest.txt", "rw"); FileChannel outputChannel = outputFile.getChannel() ) { long position = 0; long count = srcChannel.size(); srcChannel.transferTo(position, count, outputChannel); } catch (IOException e) { e.printStackTrace(); }
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/243387.html