顾名思义,FileChannel
就是连接到文件的Channel
。使用FileChannel
,你可以读取文件数据,以及往文件里面写入数据。Java NIO的FileChannel
是使用标准Java IO读取文件的一种替代方案。
FileChannel
不能被设置非阻塞模式,它总是以阻塞模式运行。
Opening a FileChannel
在你使用FileChannel
前,你必须先打开它。你不能直接打开一个FileChannel
。你必须通过一个InputStream
、OutputStream
或者RandomAccessFile
来获得一个FileChannel
。以下是如何通过一个RandomAccessFile
来获得FileChannel
的示例:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
Reading Data from a FileChannel
为了从FileChannel
读取数据,你需要调用其read()
方法。如下:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
首先分配一个Buffer
,从FileChannel
读取的数据将被读入Buffer
。
然后调用FileChannel.read()
方法。这个方法将数据从FileChannel
读入Buffer
。read()
方法返回的int
代表着有多少数据被读入了Buffer
。如果返回-1,代表着已经读到文件结尾。
Writing Data to a FileChannel
要将数据写入FileChannel
,你需要调用带有一个Buffer
类型参数的FileChannel.write()
方法。如下:
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);
}
注意在while-循环里面调用的FileChannel.write()
方法。我们无法保证每次write()
方法向Channel
写了多少字节。因此我们重复调用write()
直至没有数据可写为止。
Closing a FileChannel
当时使用完FileChannel
后,你必须关闭它。如下:
channel.close();
FileChannel Position
当读取或写入FileChannel
时,需要在特定position
执行。你可以通过调用position()
方法来获得FileChannel
的当前position
。
你还可以通过调用position(long pos)
来设置FileChannel
的position
。
以下是两个例子:
long pos = channel.position();
channel.position(pos + 123);
如果你设置的position
超过了文件的大小,并且尝试从Channel
读取数据,则会返回-1代表文件结尾。
如果你设置的position
超过了文件的大小,并且尝试往Channel
写入数据,文件会自动扩张至能放下position
以及写入的数据。这个可能导致"file hole",即磁盘上的物理文件在写入的数据中存在漏洞(即中间有一段完全没有任何数据)。
FileChannel Size
FileChannel
的size()
方法返回这个Channel
连接的文件大小。如下:
long fileSize = channel.size();
FileChannel Truncate
通过调用FileChannel.truncate()
方法,你可以truncate一个文件。当你truncate一个文件,你会把其截断为指定的长度。如下:
channel.truncate(1024);
这个例子将文件截断为1024字节。
FileChannel Force
FileChannel.force()
方法会将Channel
里面还未写入的数据全部刷新到磁盘。操作系统可能会将数据缓存在内存里以提升性能,因此我们无法保证你写入Channel
的数据都被写到了磁盘,直到你调用force()
方法。
force()
方法有一个boolean
类型的参数,代表是否将文件元数据(比如权限等)也刷新到磁盘。
以下是刷新数据以及元数据到磁盘的例子:
channel.force(true);
说明
发现貌似有人在看这个系列文章了,有必要说明下,这个Java NIO系列来源于jenkov.com,本文只是翻译,希望大家千万不要误会,本文不是原创。原文地址:Java NIO。