文件通道总是阻塞式的,因此不能被置于非阻塞模式。现代操作系统都有复杂的缓存和预读取机制,使得本地磁盘 I/O 操作延迟很小。
创建
FileChannel
对象不能直接创建。只能通过正在一个打开的 file 对象 (RandomAccessFile
, FileInputStream
, FileOutputStream
)上调用 getChannel()
方法获取。此方法会返回一个连接到相同文件的 FileChannel 对象并且此 FileChannel 对象具有和 file 对象相同的范根权限。
package java.nio.channels;
public abstract class FileChannel extends AbstractChannel
implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
public abstract int read(ByteBuffer dst, long position);
public abstract int write(ByteBuffer src, long position);
public abstract long size();
public abstract long position();
public abstract void position(long newPosition);
public abstract void force(boolean metaData);
public final FileLock lock();
public abstract FileLook lock(long position, long size, boolean shared) ;
public final FileLock tryLock();
public abstract FileLock tryLock(long position, long size, boolean shared);
public abstract MappedByteBuffer map(MapMode mode, long position, long size);
public static class MapMOde {
public static final MapMOde READ_ONLY;
public static final MapMode READ_WRITE;
public static final MapMode PRIVATE;
}
public abstract long transferTo(long position, long count, WritableByteChannel target);
public abstract long transferFrom(ReadableByteChannel src, long position, long count);
}
FileChannel 类本身是抽象的,可以从 getChannel()
方法获取到的实际对象是一个子类的一个实例。
FileChannel 对象是线程安全的。多个进程可以在同一个实例上并发调用方法而不会引起任何问题,不过并非所有的操作都是多线程的,影响通道位置或者影响文件大小的操作都是单线程的。如果有一个线程已经在执行会影响通道位置活文件大小的操作,那么其他尝试进行此类操作的线程必须等待。
访问文件
通底层的文件描述符一样,每个 FileChannel 都有一个叫 file position 的概念。这个值决定文件中哪一出的数据接下来将会被读或者写。从这点上看,FileChannel 类和缓冲区很类似,并且 MappedByeBuffer 类使得我们可以通过 ByteBuffer API 来访问文件数据。
FileChannel 的 position 属性是从底层的文件描述符获得的,该值同时被作为通道引用获取来源的文件对象共享。即一个对象对 position 的更新可以被另一个对象看到:
public void demoPosition() throws IOException {
try (RandomAccessFile randomAccessFile = new RandomAccessFile("C:\\works\\temp\\gc.log", "r");
FileChannel fileChannel = randomAccessFile.getChannel()
) {
// Set the file position.
randomAccessFile.seek(1000);
// this will print 1000
logger.info("file pos: {}", fileChannel.position());
// change the position using RrandomAccessFile object
randomAccessFile.seek(500);
// this will print 500
logger.info("file pos: {}", fileChannel.position());
// change the position using FileChannel object.
fileChannel.position(200L);
// then it will print 200
logger.info("file pos: {}", randomAccessFile.getFilePointer());
}
}
类似于 ByteBuffer 的 get/put 方法,当字节被 read/write 方法传输时,文件 position 会自动更新。如果 position 值达到了文件大小的值(可以用 size() 方法获得), read()
方法会返回一个文件尾条件值 (-1)。write()
方法会扩展文件的大小写入新数据。
类似于 ByteBuffer,也带有 position 参数的绝对形式的 read/write 方法。这种形式的方法在返回值时不会改变当前文件的 position 。由于通道的状态无需更新,这种绝对的读写可能会更有效率,操作请求可以直接传递到本地代码。多线程可以并发访问同一个文件而不会相互产生干扰。因为每次调用都是原子性的,并不依靠调用之间系统记住的状态。
在文件末尾之外的 position 进行一个绝对读擦做,size()
方法会返回一个 EOF。write()
会导致文件增加以容纳正在被写入的新字节。
当需要减少一个文件的 size 时,truncate()
方法会砍掉新 size 之外的所有数据。小于文件的字节的话,超出新 size 的部分会丢弃;大于文件的字节的话,文件不会被修改。这两种情况下, truncate()
方法都会产生副作用:文件的 position 会被设置为所提供的新 size 的值。
force()
方法则告诉通道强制将全部待定的修改都应用到磁盘的文件上。其参数表示方法返回前文件的元数据是否也要同步的更新到磁盘上。
文件锁定
EOF
Power by TeXt.