概念
通道是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被中断时通道会关闭。