首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Java NIO读书笔记之通路(一)

2012-12-19 
Java NIO读书笔记之通道(一)二、通道 Channel通道用于在缓冲区和位于在通道另一侧的实体之间有效的传输数据

Java NIO读书笔记之通道(一)
二、通道 Channel

通道用于在缓冲区和位于在通道另一侧的实体之间有效的传输数据。Channel类提供维持平台独立所需的抽象过程,不过仍然会模拟现代操

作系统本身的性能。通道是一种途径,借助该途径,可以用最小的总开销来模拟现代操作系统本身的性能。缓冲区则是通道内部用来发送和

接收数据的端点。

1.通道接口:

public interface Channel{

public boolean isOpen();

public void close() throws IOException;
}

所有类型的通道只有两个抽象的操作。

InterruptibleChannel是一个标记接口,当通道被使用时可以标记该通道是可以被中断的。

I/O可以广义的分为两大类别:File IO和Stream IO。那么通道也主要分为两类:文件通道和套接字通道。
文件通道:FileChannel
套接字通道:SocketChannel ServerSocketChannel DatagramChannel

Socket通道可以通过socket通道的工厂方法来创建。但是一个FileChannel对象只能在RandomAccessFile、FileInputStream、

FileOutputStream对象上调用getChannel来获取对象。

通道会链接到一个特定的IO服务,且通道实例的性能是受它所连接IO服务的特征所限制。一个链接到只读文件的Channel是不能进行写操作

的,否则会抛出NonWritableChannelException

在一个通道上多次调用close方法是没有坏处的,但是如果第一次调用的close正在阻塞,那么其他任何调用的close都会阻塞。在已经关闭

的Channel上调用close不会产生任何操作,只会立即返回。

2.矢量IO(Scatter/Gather)

矢量IO是指可以在多个缓冲区上实现一个简单的IO操作。对于一个Write操作而言,数据是沿着几个缓冲区顺序的沿着通道来发送。对于

read操作也是如此。每个缓冲区会被填满直至通道中的数据或者是缓冲区最大的空间被消耗完毕。
矢量IO一般都会调用操作系统本地代码来进行调用。

矢量IO接口:

public interface ScaterringByteChannel
extends ReadableByteChannel
{

public long read(ByteBuffer[] data) throws IOException;

public long read(ByteBuffer[] data, int offset, int lenght) throws IOException;
}

public interface GatheringByteChannel
extends WritabelByteChannel
{

public long write(ByteBuffer[] data) throws IOException;

public long write(ByteBuffer[] data, int offset, int length) throws IOException;
}

注意:offset和length并不是指字节区间,而是指缓冲区

long bytesread = channel.write(fiveBuffers, 1, 3);

这个方法只会在第2、3、4个缓冲区填充内容。

3.文件通道

文件通道总是阻塞模式的。
FileChannel不能够直接被创建,一个FileChannel对象只能通过RandomAccessFile、FileInputStream、FileOutputStream上调用

getChannel方法来获取。

public static void main(String[] args) throws Exception{
FileOutputStream fis = new FileOutputStream("D:\\nio_test.txt");
ByteBuffer[] buffers = new ByteBuffer[10000];
for(int i = 0; i < 10000; i++){
buffers[i] = ByteBuffer.wrap(new byte[]{(byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o',

(byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'H',

(byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'H', (byte)'e',

(byte)'l', (byte)'l', (byte)'o'});
}

long beginTime = System.currentTimeMillis();
FileChannel channel = fis.getChannel();
channel.write(buffers);
channel.close();
long endTime = System.currentTimeMillis();
System.out.println("Use time:" + (endTime - beginTime));
}

上面的代码在我的烂机器上运行只需要87ms

FileChannel对象是线程安全的,多个进程可以在同一个实例上并发调用方法而不会引起任何问题,但是如果一个线程已经在执行会影响通

道位置或文件大小的操作,那么其他需要操作此通道的线程需要等待。

FileChannel 接口:

public Abstract class FileChannel
extends AbstractChannel
implements ByteChannel, GatheringByteChannel, ScatteringByteChannel
{

public abstract long position();

public abstract void position(long position);

public abstract int read(ByteBuffer buffer);

public abstract int read(ByteBuffer buffer, long position);

public abstract int write(ByteBuffer buffer);

public abstract int write(ByteBuffer buffer, long position);

public abstract long size();

public abstract void truncate(long size);

public abstract void force(boolean metaData);

}

注意:FileChannel的position是从底层文件描述符获取的,这就意味着该position同时被作为通道引用获取来源的文件对象共享,一个对象

对position的更新,另一个对象会看到:

public static void main(String[] args) throws Exception{
RandomAccessFile rf = new RandomAccessFile("D:\\nio_test.txt", "r");
rf.seek(1000);
FileChannel channel = rf.getChannel();
System.out.println(channel.position());  //1000
channel.close();
}

当有线程去调用read和write时,position的值会自动更新,如果position到达了文件大小的值,read将会返回一个文件末尾条件值-1,如

果进行write时超过另外文件大小的值,该文件会被扩展,以容纳新写入的字节。

force方法会告诉操作系统将全部待定的修改都应用到磁盘的文件上,现代文件系统都会缓存数据和延迟磁盘文件更新以提升性能,调用

force方法要求文件所有待定修改立即同步到磁盘当中。布尔型参数表示是否同步文件的元数据,元数据是指文件的所有者、访问权限等信

息,需要操作系统底层一次额外的IO操作。大量事务处理程序可以指定为false来获得较高的性能提升。

4.文件锁定

Java NIO提供了文件锁定的支持。
与文件锁定相关的接口:

public abstract class FileChannel
extends AbstractChannel
implements ByteChannel, GatheringByteChannel, ScaterringByteChannel
{

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方法可以指定文件内部锁定区域的position和锁定区域的size,第三个参数表示是获得共享锁还是独占锁。获得共享锁时

需要以只读权限去打开文件,请求锁时需要以写权限去打开文件。

锁定的区域不一定要限制在文件的范围之内,锁可以扩展从而超出文件尾。这样就可以把待写数据区域进行保护。
fileChannel.lock(0L, Long.MAX_VALUE, false)

tryLock是非阻塞的,如果请求的锁不能够立即获得,那么将会返回null
对象锁接口:

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)  //判断position到size的区域是否在该锁定范围之内

public abstract boolean isValid();

public abstract void release() throws IOException;  //锁用完之后一定要手工释放啊啊啊啊啊!!!!

}

热点排行