?FileChannel 是一个连接到文件的通道,使用 FileChannel 可以从文件读数据,也可以向文件中写入数据。Java NIO 的 FileChannel 是标准 Java IO 读写文件的替代方案。
?FileChannel 不能设置为非阻塞的模式,也就是说 FileChannel 总是阻塞的。
?1、开启 FileChannel
?在使用 FileChannel 之前必须先开启。但是不能直接开启一个 FileChannel,需要通过一个 InputStream、OutputStream 或者 RandomAccessFile 获取它。下面是一个使用 RandomAccessFile 获取一个 FileChannel 对象的示例:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
?2、从 FileChannel 中读取数据
?从 FileChannel 中读取数据可以通过调用其中的一个 read() 方法完成,下面是一个示例:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);//将 Channel 中的数据读入到 Buffer
?首先要分配一个 Buffer,然后调用 FileChannel 的 read() 方法。从 FileChannel 中读取数据就是将该 FileChannel 中的数据读取到分配的 Buffer 中。read() 方法的返回值就是向 Buffer 中读取了多少个字节,如果返回 -1,则说明该文件已经被读取完了。
?3、向 FileChannel 中写入数据
?向 FileChannel 中写入数据需要调用 FileChannel 的 write() 方法,将 Buffer 对象作为该方法的入参,示例如下:
String newData = "New String to write to file..." + System.currentTimeMillis();ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());buf.flip();while(buf.hasRemaining()) {
channel.write(buf);// 将 Buffer 中的数据写入到 Channel 中
}
?注意:要将 FileChannel.write() 方法的调用放在一个 while 循环中,因为无法保证 write() 方法一次能将 Buffer 中的多少字节写入到 FileChannel 中,因此我们需要重复的调用 write() 直到 Buffer 中没有字节可以写。
?4、关闭 FileChannel
?FileChannel 使用完之后必须关闭,示例如下:
channel.close();
?5、FileChannel 的 position
?如果想在 FileChannel 的某一个指定位置读写数据,可以通过调用 FileChannel 的 position() 方法来获取当前的 position 值,也可以调用 FileChannel 的 position(long pos) 方法设置 position 的值,示例如下:
long pos = channel.position();channel.position(pos +123);
?如果设置的 position 值超出了 File 文件的最后位置,在读取该 Channel 时就会返回 -1 ,即返回“读取到文件的末尾”的标识。但此时若向 Channel 中写入数据,该 Channel 连接的 File 会被“扩张”到这个设置的 position 值的位置,然后将数据写入到这个 File 中,这会导致该 File 带有“空洞”,存储在磁盘上的这个物理文件就会不连续。
?6、FileChannel 的 size
?FileChannel 的 size() 方法会返回这个 FileChannel 连接的 File 文件的大小,示例如下:
long fileSize = channel.size();
?7、FileChannel 的 截断
?可以调用 FileChannel.truncate() 方法截断一个 File。截断时需要指定一个长度,示例如下:
channel.truncate(1024);
?本示例将文件长度截断为1024个字节。
?8、FileChannel 的强制
?FileChannel.force() 方法会将 Channel 中所有未写入磁盘的数据强制写入磁盘。由于性能的原因操作系统可能会将一些数据缓存在内存中,因此无法确切地保证数据被写入到了磁盘,除非调用了 force() 方法。
?force() 方法采用布尔值作为参数,指明是否同时刷新文件的元数据信息(比如权限等)。
?下面是一个同时刷新数据和元数据的示例:
channel.force(true);