FileChannel

FileChannel 总是阻塞的,因此不能被设置成非阻塞模式。

FileChannel 对象不能直接创建。一个 FileChannel 实例只能通过在一个打开的 file 对象(RandomAccessFile、FileInputStream或 FileOutputStream)上调用 getChannel() 方法 获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public abstract class FileChannel extends AbstractInterruptibleChannel 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 truncate(long size);

public abstract void force(boolean metaData);

public final FileLock lock();

public abstract FileLock 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() 方法获取的实际对象是一个具体子类的一个实例 ,该子类可能使用本地代码来实现以上 API 方法中的一些或全部。

FileChannel 对象是线程安全的。多个进程可以在同一个实例上并发调用方法而不会引起任何问题,不过并非所有的操作都是多线程的。影响通道位置或者影响文件大小的操作都是单线程的。如果有一个线程已经在执行会影响通道位置或文件大小的操作,那么其他试进行此类操作之一的线程必须等待。

FileChannel 是一个反映 Java 虚拟机外部一个具体对象的抽象。

FileChannel 类保证同一个 Java 虚拟机上的所有实例看到的某个文件的视图均是一致的。

每个 FileChannel 对象都同一个文件描述符(file descriptor)有一对一的关系。

FileChannel、RandomAccessFile 和 POSIX I/O system calls 三者在 方法上的对应关系。

FileChannel RandomAccessFile POSIX system call
read( ) read( ) read( )
write( ) write( ) write( )
size( ) length( ) fstat( )
position( ) getFilePointer( ) lseek( )
position (long newPosition) seek( ) lseek( )
truncate( ) setLength( ) ftruncate( )
force( ) getFD().sync( ) fsync( )

每个 FileChannel 都有一个 position 值来决定文件中哪一处的数据接下来被读或者写。

如果试将通道 position 设置为一个负值会导致 java.lang.IllegalArgumentException 异常。

把 position 设置到超出文件 ,这样做会把 position 设置为指定值而不改变文件大小。

FileChannel 位置(position)是从底层的文件 述符获得的,该 position 同时被作为通道引用 获取来源的文件对象共享。这也就意味着一个对象对该 position 的更新可以被另一个对象看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
RandomAccessFile randomAccessFile = new RandomAccessFile ("filename", "r");

randomAccessFile.seek (1000);

FileChannel fileChannel = randomAccessFile.getChannel( );

// This will print "1000"
System.out.println ("file pos: " + fileChannel.position( ));

randomAccessFile.seek (500);

// This will print "500"
System.out.println ("file pos: " + fileChannel.position( ));

fileChannel.position (200);

// This will print "200"
System.out.println ("file pos: " + randomAccessFile.getFilePointer( ));

当需要减少一个文件的 size 时,truncate( )方法会 您所指定的新 size 值之外的所有数据。

如果当前 size 大于新 size,超出新 size 的所有字节都会被丢弃。

如果提供的新 size 值大于或等于当前的文件 size 值,该文件不会被修改。

调用 truncate() 方法后 position 会被设置成提供的新 size。

force() 方法告诉通道强制将全部待定的修改都应用到磁盘的文件上。所有的现代文件系统都会缓存数据和延迟磁盘文件更新以提高性能。调用 force( )方法要求文件的所有待定修改立即同步到磁盘。

【参考资料】

  1. Java Nio

—EOF—