概念
通道是NIO提供的一个全新的东西,提供与I/O服务的直接连接。Channel用于在字节缓冲区和位于通道的另一侧的实体(通常是一个文件或者套接字)之间进行有效的传输数据。
接口定义
public interface Channel extends Closeable {
public boolean isOpen();
public void close() throws IOException;
}
很简单,只有一个打开和关闭的方法定义,主要的实现还是实现它的接口。
创建通道
Channel广义的可以分为两类:
文件(File)通道:涉及到的类主要是FileChannel。
套接字(socket)通道:涉及到的类主要是SocketChannel,ServerSocketChannel,DatagramChannel。
FileChannel
FileChannel能在File级别或者FileInputStream或者FileOutStream级别上获取到。
RandomAccessFile raf = new RandomAccessFile("D:/sss","r");
FileChannel fc = raf.getChannel();
FileInputStream fio = new FileInputStream("D:/sss");
FileChannel fc = fio.getChannel();
SocketChannel
SocketChannel sc = SocketChannel.open( );
sc.connect (new InetSocketAddress ("hostaddress", port));
ServerSocketChannel
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(port));
DatagramChannel
DatagramChannel dc = DatagramChannel.open( );
上面都是一些基础的打开操作,基于本人没有实际使用经验,没有其他可以分享的体验了^_^。
通道使用
使用原则
通道的使用基础是和ByteBuffer打交道,要么是数据传输给ByteBuffer对象或者从ByteBuffer对象获取数据进行传输。
使用方式的判断
通道分为单向或者双向。通道可以实现ReadableByteChannel接口用作read功能,或者可以实现WriteableByteChannel接口实现write功能。两者实现其一定义为单向,实现两个则定义为双向通道。
public interface ByteChannel
extends ReadableByteChannel, WritableByteChannel
{
}
ByteChannel实现了两个接口,它是双向通道,它本身没有任何一个方法,只是作为一个类似于中间人的便捷接口。
使用方式
书中给出的经典例子,不是很难理解public static void main(String[] args) throws IOException {
ReadableByteChannel source = Channels.newChannel(System.in);
WritableByteChannel dest = Channels.newChannel(System.out);
channelCopy1(source, dest);
// channelCopy2 (source, dest);
source.close();
dest.close();
}
private static void channelCopy1(ReadableByteChannel src, WritableByteChannel dest)
throws IOException{
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1)
{
// 切换为读状态
buffer.flip();
// 不能保证全部写入
dest.write(buffer);
// 释放已读数据的空间,等待数据写入
buffer.compact();
}
// 退出循环的时候,由于调用的是compact方法,缓冲区中可能还有数据
// 需要进一步读取
buffer.flip();
while (buffer.hasRemaining())
{
dest.write(buffer);
}
}
private static void channelCopy2(ReadableByteChannel src, WritableByteChannel dest)
throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1)
{
// 切换为读状态
buffer.flip();
// 保证缓冲区的数据全部写入
while (buffer.hasRemaining())
{
dest.write(buffer);
}
// 清除缓冲区
buffer.clear();
}
// 退出循环的时候,由于调用的是clear方法,缓冲区中已经没有数据,不需要进一步处理
}
通道关闭
1.通过close方法关闭通道,可能会出现通道在关闭底层I/O时会阻塞。但是多次调用close方法是可以多次调用的,不会产生问题。
2.可以通过isopen()方法判断通道是否开放。关闭的情况下使用会抛出ClosedChannelException。
3.I/O被中断时通道会关闭。