Channel是java在NIO继Buffer的第二大创新。Channel 提供到I/O服务的直接连接。Channel 是在字节Buffer和Channel 另一端的实体(通常是文件或套接字)之间有效传输数据的媒介。通常Channel 与操作系统文件描述符是一对一的关系。Channel 类提供了维护平台独立性所需的抽象,但仍然对现代操作系统的本地I/O功能建模。Channel 是网关,通过它可以以最少的开销访问操作系统的本地I/O服务,Buffer是Channel 用来发送和接收数据的内部端点。
NIO Channel 基础
从顶层Channel接口可以看到,所有通道只有两个通用的操作:检查通道是否打开isOpen
和关闭打开的通道close
package java.nio.channels;
public interface Channel
{
public boolean isOpen();
public void close() throws IOException;
}
打开Channel
众所周知,I/O分为两大类:文件I/O和流I/O。 对应通道Channel 有两种类型通道。文件Channel 和套接字Channel 。 FileChannel类和SocketChannel类用于处理这两个类别。
FileChannel对象只能通过RandomAccessFile
,FileInputStream
或FileOutputStream
对象上调用getChannel()
方法才能获得。 不能直接创建FileChannel对象。
public class OpeningFileChannels {
public static void main(String[] args) throws FileNotFoundException {
RandomAccessFile raf = new RandomAccessFile ("somefile", "r");
FileChannel fc = raf.getChannel();
}
}
与FileChannels相反,套接字通道具有工厂方法来直接创建新的套接字通道。 例如
public class OpeningSocketChannels {
public static void main(String[] args) throws IOException {
//How to open SocketChannel
SocketChannel sc = SocketChannel.open();
sc.connect(new InetSocketAddress("localhost", 9090));
//How to open ServerSocketChannel
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind (new InetSocketAddress(8080));
//How to open DatagramChannel
DatagramChannel dc = DatagramChannel.open();
}
}
使用Channels
大多数读/写操作由从下面的接口实现的方法执行。
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
{
}
通道可以是单向或双向的。 给定的通道类可能实现ReadableByteChannel,它定义了read()方法。 另一个可能实现WritableByteChannel以提供write()。 实现这些接口中的一个或另一个的类是单向的:它只能在一个方向上传输数据。 如果一个类实现两个接口(或扩展两个接口的ByteChannel),则它是双向的,可以双向传输数据。
Channels例子
在下面的示例中,我们将数据从一个通道复制到另一个通道(或从一个文件复制到另一个文件):
public class ChannelCopyExample
{
public static void main(String args[]) throws IOException
{
FileInputStream input = new FileInputStream ("testIn.txt");
ReadableByteChannel source = input.getChannel();
FileOutputStream output = new FileOutputStream ("testOut.txt");
WritableByteChannel dest = output.getChannel();
copyData(source, dest);
source.close();
dest.close();
}
private static void copyData(ReadableByteChannel src, WritableByteChannel dest) throws IOException
{
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1)
{
// Prepare the buffer to be drained
buffer.flip();
// Make sure that the buffer was fully drained
while (buffer.hasRemaining())
{
dest.write(buffer);
}
// Make the buffer empty, ready for filling
buffer.clear();
}
}
}