Java NIO
ByteBuffer
ByteBuffer
使用byte[]数组存储
-
capacity
数组长度 -
limit
第一个不可读取或写入的index -
mark
标记当前position,通过reset返回到mark位置 -
position
下一个要读取或写入的index -
int remaining()
获取剩余容量: limit-position
0<mark<position<limit<capacity
- 判断缓冲区是否只读
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[] {1, 2, 3, 4, 5, 6});
System.out.println(byteBuffer.isReadOnly()); // false
- 直接缓冲区
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[] {1, 2, 3, 4, 5, 6});
System.out.println(byteBuffer.isDirect()); // false
- 还原缓冲区状态
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
position=1; limit=capacity; mark=-1;
- 对缓冲区进行反转 flip()
将指针设置为0,mark设置为-1,当前位置设置为不可读写的位置
将限制设置为当前位置
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
// 测试
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
buffer.put(new byte[] {1, 2, 3, 4, 5, 6}, 2, 3);
// buffer.rewind();
buffer.flip();
while (buffer.hasRemaining())
{
System.out.println(buffer.get());
}
// 3 4 5
- remind()
将指针设置为0,mark设置为-1
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
// 测试
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
buffer.put(new byte[] {1, 2, 3, 4, 5, 6}, 2, 3);
buffer.rewind();
while (buffer.hasRemaining())
{
System.out.println(buffer.get());
}
// 3 4 5 0 0 0 0 0 0 0
-
putLong()
将8个字节put到缓冲区中,如putLong(1) --> 1 2 3 4 5 6 7 8
高位/低位 array() 字节顺序 -
asCharBuffer 视图转换
两个字节转为一个字符 e.g
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
buffer.put(new byte[] {0, 98, 0, 99, 0, 100, 0, 101, 0, 102}); // StandardCharsets.UTF-16BE
buffer.rewind();
CharBuffer charBuffer = buffer.asCharBuffer();
while (charBuffer.hasRemaining())
{
System.out.println(charBuffer.get());
}
// b c d e f
直接缓冲区和堆缓冲区
- 直接缓冲区的内存分配和释放的成本要高于非直接缓冲区。因此不要频繁的创建直接缓冲区
-
slice()
内存共享缓冲区 -
压缩缓冲区
byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.position(2);
buffer.compact();
System.out.println("current position:" + buffer.position()); // 8
buffer.rewind();
while (buffer.hasRemaining())
{
System.out.println(buffer.get());
}
3
4
5
6
7
8
9
10
9
10
- duplicate 复制缓冲区
新缓冲区的内容一样,内存共享
Channel
通道概述
通道:数据传输的通路
NIO是将数据放在缓冲区进行管理,再利用通道进行数据传输到目的地
channel
jdk1.8 通道子接口
- AsynchronousChannel
- AsynchronousByteChannel
- ReadableByteChannel
- ScatteringByteChannel
- WriteableByteChannel
- GatheringByteChannel
- ByteChannel
- SeekableByteChannel
- NetworkChannel
- MulticastChannel
- InterruptipleChannel
-
AsynchronousChannel
使通道支持异步IO操作
(1)Futureoperation()
Future用来判断IO操作是否完成,或者等待完成
(2)回调的方式
void operation(... A attachment, CompletionHandler<V, supper A> handler)
-
ReadableByteChannel
只允许一个线程read,第二个会被阻塞
1) 将通道当前位置读到ByteBuffer中
2) read(ByteBuffer )是同步的 -
ScatteringByteChannel
从通道中读取字节到多个缓冲区
public long read(ByteBuffer[] dsts) throws IOException;
-
GatheringByteChannel
将多个缓冲区的内容写到通道中 -
ByteChannel
整合ReadableByteChannel和WriteableChannel -
SeekableByteChannel
允许position改变 -
NetworkChannel
与Socket进行关联
bind(SocketAddress)
FilChannel
Charset charset = Charset.forName("UTF-8");//Java.nio.charset.Charset处理了字符转换问题。它通过构造CharsetEncoder和CharsetDecoder将字符序列转换成字节和逆转换。
CharsetDecoder decoder = charset.newDecoder();
System.out.println(System.getProperty("user.dir"));
FileInputStream fis = new FileInputStream("nio/src/main/resources/aa.txt");
FileChannel fileChannel = fis.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
CharBuffer charBuffer = CharBuffer.allocate(4);
int i = 0;
while (fileChannel.isOpen() && fileChannel.read(byteBuffer) != -1)
{
System.out.print("第" + (++i) + "次填充byte缓冲区,长度为:" + byteBuffer.position());
byteBuffer.flip();
decoder.decode(byteBuffer, charBuffer, true);
System.out.println(" char decode use length=" + byteBuffer.position());
charBuffer.flip();
while (charBuffer.hasRemaining())
{
System.out.println(" 转换为char缓冲区,charBuffer[" + charBuffer.position() + "]=" + charBuffer.get());
}
charBuffer.clear();
System.out.println();
byteBuffer.compact(); // 压缩,把未使用的压缩到前面
}
# 输入 aa.txt
大型社死现场
# 输出
第1次填充byte缓冲区,长度为:4 char decode use length=3
转换为char缓冲区,charBuffer[0]=大
第2次填充byte缓冲区,长度为:4 char decode use length=3
转换为char缓冲区,charBuffer[0]=型
第3次填充byte缓冲区,长度为:4 char decode use length=3
转换为char缓冲区,charBuffer[0]=社
第4次填充byte缓冲区,长度为:4 char decode use length=3
转换为char缓冲区,charBuffer[0]=死
第5次填充byte缓冲区,长度为:4 char decode use length=3
转换为char缓冲区,charBuffer[0]=现
第6次填充byte缓冲区,长度为:3 char decode use length=3
转换为char缓冲区,charBuffer[0]=场
分析:第一次读取四个字节:[1,2,3,4],在字符解码时,使用了三个字节转码为 ‘大’,使用压缩方法将剩余的未使用的字节压缩到开头,然后继续从后面读取,以此反复操作。
由此可知:中文一个字符占用三个字节,数字、英文字母占用一个字节