通道(Channel)用于在字节缓冲区(通道只能在字节缓冲区上操作)和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据,并且通道往往是和操作系统的文件描述符(File Descriptor)和文件句柄(File Handle)对应的,可以用最小的总开销来访问操作系统本身的I/O服务
通道基础
如下所示
基本的Channel接口源码
package java.nio.channels; public interface Channel { public boolean isOpen( ); //通道是否打开 public void close( ) throws IOException; //关闭一个打开的通道}
InterruptibleChannel是一个标记接口,标示该通道是可以中断的(Interruptible),如果连接可中断通道的线程被中断,那么该通道会以特别的方式工作。大多数但非全部的通道都是可以中断的
类层次结构中有两个类位于一个不同的包:java.nio.channels.spi。这两个类AbstractInterruptibleChannel和AbstractSelectableChannel,它们分别为可中断的(interruptible)和可选择的(selectable)的通道实现提供所需的常用方法
打开通道
IO可以分为File I/O和Stream I/O,通道也可以分为文件(file)通道和套接字(socket)通道,最常用的分别是FileChannel类和三个socket通道类:SocketChannel、ServerSocketChannel和DatagramChannel
Socket通道有可以直接创建新socket通道的工厂方法。但是一个FileChannel对象却只能通过在一个打开的RandomAccessFile、FileInputStream或FileOutputStream对象上调用getChannel( )方法来获取
package com.henrysun.javaSE.niostudy;import java.io.IOException;import java.io.RandomAccessFile;import java.net.InetSocketAddress;import java.nio.channels.DatagramChannel;import java.nio.channels.FileChannel;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;/** * 打开通道 */public class ChannelOpen { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { SocketChannel sc = SocketChannel.open(); sc.connect(new InetSocketAddress("somehost", 8080)); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(8090)); DatagramChannel dc = DatagramChannel.open(); RandomAccessFile raf = new RandomAccessFile("somefile", "r"); FileChannel fc = raf.getChannel(); }}
使用通道
上面的类图结构,大部分零乱部分移除可以得到如下的UML图
public interface ReadableByteChannel extends Channel { public int read(ByteBuffer dst) throws IOException;}public interface WritableByteChannel extends Channel { public int write(ByteBuffer src) throws IOException;}public interface ByteChannel extends ReadableByteChannel, WritableByteChannel {}
通道可以是单向的或者双向的,一个channel类可能实现定义read( )方法的ReadableByteChannel接口,而另一个channel类也许实现WritableByteChannel接口以提供write( )方法。实现这两种接口其中之一的类都只能在一个方向上传输数据。如果一个类同时实现这两个接口,那么它可以双向传输数据。这对于sockets不是问题,因为它一直是双向的,但是从FileInputStream对象的getChannel( )方法获取的FileChannel对象是只读的,因为FileInputStream对象总是以read-only的权限打开文件,尽管FileChannel实现了ByteChannel接口。调用write( )方法将抛出未经检查的NonWritableChannelException异常
通道可以以阻塞和非阻塞模式运行。非阻塞模式的通道永远不会让调用的线程休眠。请求的操作要么立即完成,要么返回一个结果表明未进行任何操作。只有面向流的(stream-oriented)的通道,如sockets和pipes才能使用非阻塞模式
注:socket通道类从SelectableChannel引申而来。从SelectableChannel引申而来的类可以和支持有条件的选择(readiness selectio)的选择器(Selectors)一起使用。将非阻塞I/O和选择器组合起来可以使您的程序利用多路复用I/O(multiplexed I/O)