nio 的基本组成
1. Buffer
高效的数据容器,除布尔类型,所有原始数据类型都有Buffer实现。
使用步骤:
- 写入数据到 Buffer
- 调用
flip()
方法调整指针位置准备读取 - 从 Buffer 中读取数据
- 调用
clear()
方法或者compact()
方法清理缓存
主要属性值:
capacity
:Buffer缓冲区大小,只能写入capacity个原始类型。不会改变。position
:下一个要被读写的数据的索引。limit
:第一个不被读写的数据的索引位置,通常就是缓冲区中实际数据的字节数。
主要方法:
flip()
:反转缓冲区,将limit的值设为position的值, 然后position的值设为0。为从缓冲区读取字节做准备。rewind()
:从头再读或再写,limit不变,position设置为0。mark()
:标记当前的position值,和reset()配合使用。reset()
:将当前position设为mark标记的值。hasRemaining()
:position和limit之前是否还有元素。clear()
:清空整个缓冲区(没有擦除)。 position的值设为0, limit的值设为capacity,mark的值被丢弃。为把字节写到缓冲区做准备。compact()
:只清空已经读过的数据(没有擦除)。未读数据复制到缓冲区的起始处,position设到最后一个未读数据后。
Buffer的分配:要想获得一个Buffer对象首先要进行分配。 每一个Buffer类都有一个静态 allocate(int)
方法。
写数据到Buffer 有两种方式:
- 从 Channel 写到 Buffer。
- 通过 Buffer 的 put() 方法写到 Buffer 里。
从Buffer中读取数据 有两种方式:
- 从Buffer读取数据到Channel。
- 使用get()方法从Buffer中读取数据。
equals()
,当满足下列条件时,表示两个Buffer相等:
- 有相同的类型(byte、char、int等)。
- Buffer中剩余的byte、char等的个数相等。
- Buffer中所有剩余的byte、char等都相同。
compareTo()
,比较两个同类型Buffer的剩余元素, 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:
- 第一个不相等的元素小于另一个Buffer中对应的元素 。
- 所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。
ByteBuffer
ByteBuffer 是唯一直接与通道交互的缓冲器。
静态方法:
ByteBuffer wrap(byte[] array)
:使用“支持”数组初始化一个 ByteBuffer,数组的和缓存器的数据相互关联。
实例方法:
asXXBuffer 系列方法
可以获得特定基本数据类型的视图。ByteBuffer 依然是实际存储数据的地方。slice()
创建新的 ByteBuffer 对象,和原来对象的字节数据相互关联,它们的区别是指针对象相互独立。
2. Charset
把字符集包装为对象,提供字符集的编码器和解码器。
Charset.forName("UTF-8").encode("Hello World!");
3. Channel
Java NIO 的通道类似流,但又有些不同:
- 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
- 通道可以异步地读写。
- 通道中的数据总是要先读到Buffer,或者总是要从Buffer中写入。
主要的通道实现:
- FileChannel 从文件中读写数据,它必须阻塞,不能用在非阻塞模式中。
- DatagramChannel 能通过UDP读写网络中的数据。
- SocketChannel 能通过TCP读写网络中的数据。
- ServerSocketChannel 可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
a. FileChannel
创建:
无法直接打开一个FileChannel,需要通过 InputStream、OutputStream 或 RandomAccessFile 的 getChannel 方法来获取一个 FileChannel 实例。
FileChannel 常用方法:
read(ByteBuffer)
,从文件通道读取数据到ByteBuffer,-1 表示已经到达输入的末尾。write(ByteBuffer)
,从字节缓存区写到文件通道。close()
,关闭。transferFrom()
,将数据从源通道传输到FileChannel中toChannel.transferFrom(position, count, fromChannel);
transferTo()
,将数据从FileChannel传输到其他的channel中fromChannel.transferTo(position, count, toChannel);
FileChannel其它方法:
position()
获取当前位置position(int)
设置当前位置size()
返回该实例所关联文件的大小- truncate(int) 截取文件的前int个字节
- force(boolean) 将通道里尚未写入磁盘的内存缓存数据强制写到磁盘上,boolean指明是否同时将文件元数据(权限信息等)写到磁盘上
Scattering Reads,数据从一个channel读取到多个buffer中。不适用于动态消息(消息大小不固定)。
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
Gathering Writes 是指数据从多个buffer写入到同一个channel。能较好的处理动态消息。
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(10