FileChannel 提供了一种通过通道来访问文件的方式,它可以通过带参数 position(int) 方法定位到文件的任意位置开始进行操作,还能够将文件映射到直接内存,提高大文件的访问效率。本文将介绍其详细用法和原理。
- 通道获取
FileChannel 可以通过 FileInputStream, FileOutputStream, RandomAccessFile 的对象中的 getChannel() 方法来获取,也可以同通过静态方法 FileChannel.open(Path, OpenOption …) 来打开。
1.1 从 FileInputStream / FileOutputStream 中获取
从 FileInputStream 对象中获取的通道是以读的方式打开文件,从 FileOutpuStream 对象中获取的通道是以写的方式打开文件。
FileOutputStream ous = new FileOutputStream(new File(“a.txt”));
FileChannel out = ous.getChannel(); // 获取一个只读通道
FileInputStream ins = new FileInputStream(new File(“a.txt”));
FileChannel in = ins.getChannel(); // 获取一个只写通道
1.2 从 RandomAccessFile 中获取
从 RandomAccessFaile 中获取的通道取决于 RandomAccessFaile 对象是以什么方式创建的,“r”, “w”, “rw” 分别对应着读模式,写模式,以及读写模式。
RandomAccessFile file = new RandomAccessFile(“a.txt”, “rw”);
FileChannel channel = file.getChannel(); // 获取一个可读写文件通道
1.3 通过 FileChannel.open() 打开
通过静态静态方法 FileChannel.open() 打开的通道可以指定打开模式,模式通过 StandardOpenOption 枚举类型指定。
FileChannel channel = FileChannel.open(Paths.get(“a.txt”), StandardOpenOption.READ); // 以只读的方式打开一个文件 a.txt 的通道
2. 读取数据
读取数据的 read(ByteBuffer buf) 方法返回的值表示读取到的字节数,如果读到了文件末尾,返回值为 -1。读取数据时,position 会往后移动。
2.1 将数据读取到单个缓冲区
和一般通道的操作一样,数据也是需要读取到1个缓冲区中,然后从缓冲区取出数据。在调用 read 方法读取数据的时候,可以传入参数 position 和 length 来指定开始读取的位置和长度。
FileChannel channel = FileChannel.open(Paths.get(“a.txt”), StandardOpenOption.READ);
ByteBuffer buf = ByteBuffer.allocate(5);
while(channel.read(buf)!=-1){
buf.flip();
System.out.print(new String(buf.array()));
buf.clear();
}
channel.close();
2.2 读取到多个缓冲区
文件通道 FileChannel 实现了 ScatteringByteChannel 接口,可以将文件通道中的内容同时读取到多个 ByteBuffer 当中,这在处理包含若干长度固定数据块的文件时很有用。
ScatteringByteChannel channel = FileChannel.open(Paths.get(“a.txt”), StandardOpenOption.READ);
ByteBuffer key = ByteBuffer.allocate(5), value=ByteBuffer.allocate(10);
ByteBuffer[] buffers = new ByteBuffer[]{key, value};
while(channel.read(buffers)!=-1){
key.flip();
value.flip();
System.out.println(new String(key.array()));
System.out.println(new String(value.array()));