java.nio.Channel.java
- channel表示对于如硬件设备、文件、网络socket或program component等实体的一个打开的连接,提供一个或多个不同的I/O方法,如读和写。
- channel要么打开,要么关闭。一旦创建即打开,一旦关闭,就一直关闭。当通道关闭后,任何I/O方法都会抛出ClosedChannelException异常。
- channel是线程安全的。
与流的不同
- 既可以从通道读数据,也可以写数据。而流的读写是单向的
- 通道可以异步读写
- 通道中的数据总是要先读到一个Buffer或总是要从一个Buffer读入
不同实现
- FileChannel 从文件中读写数据。
- DatagramChannel 能通过UDP读写网络中的数据。
- SocketChannel 能通过TCP读写网络中的数据。
- ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
//使用FileChannel读取文件
public static void main(String[] args) throws IOException {
RandomAccessFile accessFile=new RandomAccessFile("input.txt","rw");
FileChannel fileChannel=accessFile.getChannel();
ByteBuffer buf=ByteBuffer.allocate(10);
int bytesRead=fileChannel.read(buf);
while(bytesRead!=-1){
System.out.println("Read"+bytesRead);
buf.flip();
while(buf.hasRemaining()){
System.out.print((char)buf.get());
}
buf.clear();
bytesRead=fileChannel.read(buf);
System.out.println();
}
fileChannel.close();
accessFile.close();
}
java.nio.Buffer.java
- buffer是一个线性、有限元素序列,存放特定的基本数据类型。
- capacity是buffer可以容纳元素的数目
- limit表示从下标limit开始,后面的元素都不再读或写了
- position是下一个要读或写的元素下标
- 实例对象本质上是一块可写可读的内存区域
- 一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。
//通道read到buffer,然后要get的时候用;或者put完,通道要把buffer write的时候
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
//重读
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
- 通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。
- equals()只比较Buffer中的剩余元素是否相等。
- compareTo()方法比较两个Buffer的剩余元素
gather/scatter
Scattering Reads是指数据从一个channel读取到多个buffer中
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
当一个buffer被写满后,channel紧接着向另一个buffer中写。
Gathering Writes是指数据从多个buffer写入到同一个channel
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
//write data into buffers
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);
这里只会把buffer里的有效数据写入,不会像读数据一样(读满一个buffer再下一个)
Selector
Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。(不需要一个连接一个线程了)