FileChannel原理
Posted zhya
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于FileChannel原理的主要内容,如果未能解决你的问题,请参考以下文章
使用 FileChannel 和 ByteArrays 读取 ASCII 文件