FileChannel,顾名思义,它就是一个连接到一个文件的通道,我们可以通过通道读写以及操作文件。
先来看看Java API 对FileChannel的部分描述:
public abstract class FileChannel extends AbstractInterruptibleChannel implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
A channel for reading, writing, mapping, and manipulating a file.
A file channel is a SeekableByteChannel
that is connected to a file. It has a current position within its file which can be both queried
and modified
. The file itself contains a variable-length sequence of bytes that can be read and written and whose current size
can be queried. The size of the file increases when bytes are written beyond its current size; the size of the file decreases when it is truncated
. The file may also have some associated metadata such as access permissions, content type, and last-modification time; this class does not define methods for metadata access.
从上面的描述中可以看出,在FileChannel上我们可以进行读、写、映射和操纵文件等。它是一个可查找的字节通道,以及一个可以遍历和修改的position属性。当我们往文件中写入字节时,如果position超过了文件的位置,文件的大小就会变大,如果我们截取了文件,那么文件的大小就会变小。
1. 打开FileChannel。可以通过FileInputStream,FileOutputStream以及RandomAccessFile来获取一个FileChannel的实例。
Example:
/** * 打开一个文件 */ RandomAccessFile raFile = new RandomAccessFile("file_path", "rw"); /** * 通过RandomAccessFile的getChannel()方法获取一个到达该文件的FileChannel */ FileChannel fChannel = raFile.getChannel();
2. 从FileChannel读数据
2.1 分配一个Buffer。从FileChannel中读取的数据将被读到Buffer中。
2.2 调用FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。read()方法返回的
int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。
Example:
/** * 分配一个Buffer */ ByteBuffer buf = ByteBuffer.allocate(48); /** * 调用FileChannel的read方法 */ int bytesRead = fChannel.read(buf);
/** * 要写入FileChannel的数据 */ String data = "..."; /** * 分配一个Buffer */ ByteBuffer buf = ByteBuffer.allocate(48); /** * 清空Buffer */ buf.clear(); /** * 将数据放入Buffer中 */ buf.put(data.getBytes()); /** * 从读模式转换为写模式 */ buf.flip(); /** * 写入 */ while(buf.hasRemaining()) { channel.write(buf); }
4. 关闭FileChannel。调用fChannel的close()方法即可关闭通道。注意,使用完Channel后必须将其关闭。
通过调用position()方法获取FileChannel的当前操作到的位置,也可以通过调用position(long pos)方法设置FileChannel的位置。
如果将位置设置在文件结束符之后,然后试图从文件通道中读取数据,读方法将返回-1,即代表文件结束。
如果将位置设置在文件结束符之后,然后向通道中写数据,文件将撑大到当前位置并写入数据。这可能导致“文件空洞”,磁盘上物理文件中写入的数据间有空隙。
将返回该实例所关联文件的大小。
截取一个文件。截取文件时,指定长度后面的部分将被删除。
将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。
参考资料:
[1]. Java 2 SE 7 Documentation Package java.nio
[2]. 并发编程网 Java NIO系列教程