JavaNIO-文件通道

文件通道,是一种特殊的通道。
对于文件通道来说,是不能阻塞的。所以并不能设置非阻塞模式。
对于异步文件I/O来说,这是很多操作系统支持的,NIO也会增强。

一个FileChannel只能从RandomAccessFile,FileInputStream和FileOutputStream来获取(getChannel),然后你就获得了某种能力,请看:

package java.nio.channels; public abstract class FileChannel extends
AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
// This is a partial API listing
// All methods listed here can throw java.io.IOException
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)
}


以上的操作,都会抛出java.io.IOException
FileChannel对象是线程安全的,但是注意的是,影响到通道位置和文件大小的操作是单线程的。

对于同一个虚拟机,我们看到的对于某一个文件的FileChannel实例视图都是一致的。
FileChannel对于的操作和POSIX中的一些API函数很相像。
[table]
FileChannel|RandomAccessFile|POSIX system call
read()|read()|read()\n
write()|write()|write()\n
size()|length()|fstat()\n
position()|getFilePointer()|lseek()\n
position(long newPosition)|seek()|lseek()\n
truncate()|setLength()|ftruncate()\n
force()|getFD().sync()|fsync()\n
[/table]

FileChannel里有一个position属性,表示下一个要读取的文件位置。这个和缓冲区有点像。但是可以超过这个值。如果write的position超过了文件大写,就会增大文件,有可能造成空洞文件。如果是read的话,到达文件尾,则是返回-1.
如果带有一个long参数的position则可以设置文件的位置大小,这是并不改变文件大小。只有当read或者write的时候,才真正的改变。

注意position是从底层描述符中得来的,被作为通道引用获去来源的文件共享对象,所以改变她,其他的对象可以看到。


trucate函数会把新的size以外的数据清除。如果size大于原来的size,那么position会被改变成新的size。


对于force函数,则是一个同步磁盘函数。把修改都应用到磁盘上。如果带有boolean型参数,那么表明是否要把元数据也同步。元数据是指,文件的所有者,访问权限,上次修改时间等信息。这要看具体的应用,因为同步这些信息会有额外的底层I/O操作。

文件锁。
文件锁针对的是文件,所以和通道无关。一般来说分为共享锁(shared)和独占锁(exclusive)。
注意,如果一个进程下的另一个线程访问一个加独占锁的文件,是可以的。因为这是底层操作系统的实现。只是针对不同的进程。
所以,也有可能在某些操作系统上,独占锁只是一个建议锁,非强制性的。
关于管道上的锁,有如下操作。


public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
// This is a partial API listing
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)
}

我们可以看到,lock可以锁住一个文件的某个区域。而且这个区域可以使比文件还大。
超出文件尾的。这样,新写入的内容也被锁住。使用lock可能会阻塞,等待前一个lock被释放。
tryLock和lock一样。只是如果当时没有可用锁,就立即返回一个null,而不是阻塞。
FileLock 类如下:

public abstract class FileLock {
public final FileChannel channel( )
public final long position( )
public final long size( )
public final boolean isShared( )
public final boolean overlaps (long position, long size)
public abstract boolean isValid( );
public abstract void release( ) throws IOException;
}


一旦FileLock对象创建就生效。注意,创建以后,position,是否独占,大小就不能改变了。
FileLock是线程安全的,可以多个线程同时访问一个锁。注意,在你不确定操作系统是否支持独占性时,使用isShared()来判断是否该锁支持共享。
如果你要查看一个感兴趣的区域是否与当前的锁有冲突,可以使用 overlaps,这个函数返回的是当前进程上的,即使是返回为false,也不一定可以获取到FileLock。

最后,使用文件锁,一定要释放。使用try...catch...finally

FileLock lock = fileChannel.lock( )
try {
<perform read/write/whatever on channel>
} catch (IOException)
[ <handle unexpected exception> }
finally {
lock.release( )
}


注意,FileLock是针对不同进程的。如果在一个进程内,锁是无意义的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值