Java NIO FileChannel

215 阅读3分钟

一个Java NIO FileChannel 是一个连接到文件的channel。使用一个文件channel你可以从文件里读数据,和写数据到文件。Java NIO FileChannel 类是NIO的选择reading files with the standard Java IO API.

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.write()方法来完成写数据到FileChannel,这个使用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);
}

注意FileChannel.write()方法是怎么在一个while循环里调用的。这里不保证write()方法写多少数据到FileChannel。所以我们多次重复调用write()方法直到Buffer没有更多的字节写入。

Cloasing a FileChannel

当你使用完FileChannel后必须要关闭它。这里是具体怎么做的例子:

channel.close();

FileChannel Position

当读取或者写到一个FileChannel完成这个功能使用指定的position。你可以调用position方法来获取当前FileChannel的position。

你也可以通过调用position(long pos)方法来设置FileChannel。

这里有两个例子:

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()方法来截断一个文件。当你截断一个文件,你截断它在一个给定的长度。这是一个例子:

channel.truncate(1024);

这个例子截断文件在1024字节长度处。

FileChannel Force

FileChannel.force()方法从channel将所有未写的数据flush到磁盘上。因为性能的原因操作系统也许会缓存数据在内存里,所以你不能保证已经写到channel的数据就是实际写到磁盘的数据,直到你调用force()方法。

force()方法用一个boolean变量作为参数,告诉文件元文件(permission etc.)是否也要flush。

这里是同时写数据和元数据的例子:

channel.force(true);