这个说实话挺难定义的,有点抽象,不过咱们能够根据它的用途来理解;java
通道主要用于传输数据,从缓冲区的一侧传到另外一侧的实体(如文件、套接字...),反之亦然;dom
通道是访问IO服务的导管,经过通道,咱们能够以最小的开销来访问操做系统的I/O服务;socket
顺便说下,缓冲区是通道内部发送数据和接收数据的端点,以下图所示;spa
另外,关于通道Channel接口的定义,很简单,只有两个方法,判断通道是否打开和关闭通道;操作系统
public interface Channel extends Closeable { public boolean isOpen(); public void close() throws IOException; }
通道主要分为两大类,文件(File)通道和套接字(socket)通道;线程
涉及的类有FileChannel类和三个socket通道类:SocketChannel、ServerSocketChannel和DatagramChannel;code
下面分别看下这几个通道是如何建立的:对象
FileChannel通道只能经过在一个打开的RandomAccessFile、FileInputStream或FileOutputStream对象上调用getChannel( )方法来获取,以下所示:blog
RandomAccessFile raf = new RandomAccessFile ("somefile", "r"); FileChannel fc = raf.getChannel( );
SocketChannel sc = SocketChannel.open( ); sc.connect (new InetSocketAddress ("somehost", someport));
ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(somelocalport));
DatagramChannel dc = DatagramChannel.open( );
在使用通道的时候,咱们一般都将通道的数据取出存入ByteBuffer对象或者从ByteBuffer对象中获取数据放入通道进行传输;继承
在使用通道的过程当中,咱们要注意通道是单向通道仍是双向通道,单向通道只能读或写,而双向通道是可读可写的;
若是一个Channel类实现了ReadableByteChannel接口,则表示其是可读的,能够调用read()方法读取;
若是一个Channel类实现了WritableByteChannel接口,则表示其是可写的,能够调用write()方法写入;
若是一个Channel类同时实现了ReadableByteChannel接口和WritableByteChannel接口则为双向通道,若是只实现其中一个,则为单向通道;
如ByteChannel就是一个双向通道,实际上ByteChannel接口自己并不定义新的API方法,它是一个汇集了所继承的多个接口,并从新命名的便捷接口;
以下是一个使用通道的例子,展现了两个通道之间拷贝数据的过程,已添加了完整的注释:
package nio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; public class Main { 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方法,缓冲区中已经没有数据,不须要进一步处理 } }
咱们能够经过调用close()方法来关闭通道;
一个打开的通道表明与一个特定I/O服务的特定链接,并封装该链接的状态。当通道关闭时,这个链接会丢失,而后通道将再也不链接任何东西。
能够经过isOpen()方法来判断通道是否打开,若是对关闭的通道进行读写等操做,会致使ClosedChannelException异常;
另外,若是一个通道实现了InterruptibleChannel接口,那么,当该通道上的线程被中断时,通道会被关闭,且该线程会抛出ClosedByInterruptException异常;
《Java NIO》