文件编程

19 阅读2分钟

FileChannel

File 只能工作在阻塞模式下

获取

  不能直接打开 FileChannle,必须通过 FileInputStream、FileOutputStream 或者 RandomAccessFile 来获取 FileChannle

  • 通过 FileInputStream 获取的 channel 只能读
  • 通过 FileOutputStream 获取的 channel 只能写,new FileOutputStream(file) 如果目标文件已经存在,那么会先清空 目标文件的数据,然后再写入新的数据,如果需要以追加的形式写入,那么需要使用new FileOutputStream(file,true)
  • 通过 RandomAccessFile 是否能够读写根据构造 RandomAccessFile 时的读写模式决定

读取

会从 channel 读取数据填充 ByteBuffer 返回值表示读到多少字节,-1 表示到达了文件的末尾

int readBytes = channel.read(buffer);

写入

  FileChannle 写入是没限制的,但是我们一般使用的是 SCocketChannle,而SocketChannle 写入的能力是有限的
  因为 write 方法并不能保证一次将 buffer 中的内容全部写入 channel,所以需要在 while 调用。
  channel.writ 写入的正确姿势如下:

ByteBuffer buffer = ...;
// 存入数据
buffer.put(...);
// 切换到读模式
buffer.flip();

// 判断 buffer 是否还有数据
while(buffer.hasRemaining()) {
    channel.write(buffer);
}

关闭

  channel 必须关闭,不过调用了 FileInputStream、FileOutputStream 或者 RandomAccessFile 的 close 方法会间接的调用 channle 的 close 方法

位置

设置当前位置时,如果设置为文件的末尾

  • 这时读取会返回 -1
  • 这时写入会从指定位置开始覆盖写内容,但是如果 position 超过了文件末尾,再写入时新内容和原末尾之间会有空洞(00)
  • FileOutputStream 获取的 channel position 如果使用追加写的构造函数,position 就是结尾的 position,如果是默认的,那么会清空文件再按 0 开始写
  • RandomAccessFile 获取的 position 固定是 0

获取 channel 的当前位置,即该从哪个位置读或写

channel.position()

设置 channel 的当前位置

channel.position(newPos)

强制写入

  FileChannel.force() 方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到 FileChannel 里的数据一定会即时写入到磁盘上。要保证这一点需要调用 force 方法。

  force() 方法有一个 boolean 类型的参数,指明是否将文件元数据(权限信息等)写到磁盘上。

传输数据

  FileChannel.transferTo() 和 transferFrom 可以用来传输数据,效率高,底层会利用操作系统的零拷贝进行优化。
  FileChannel 中 transferFrom 和 transferTo 方法的区别你知道吗 - Demo_Liu - 博客园 (cnblogs.com)