NIO,可以称为 New IO 或 Non Blocking IO,是在 JDK 1.4 后提供的新 API。传统的I/O 是阻塞式的 I/O、面向流的操作;而 NIO 是非阻塞 I/O 、面向通道(Channel) 和 缓冲区(Buffer) 的操作。此外,NIO 还提供了选择器(Selector)全新的概念,这些都使 NIO 在传输数据时更加高效。下图为选择器、通道和缓冲区的关系图。
Buffer 的底层是一个数组,用于存储数据。NIO 提供了 7 种类型的缓冲区,用于存储不同类型的数据:ByteBuffer、IntBuffer、ShortBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer,并且它们都继承自 java.nio.Buffer。
在 Buffer 类中有 5 个重要的属性。
1 int position:下一个将要被读或写的元素位置。
2 int limit:限制 Buffer 中能够存放的元素个数,换句话说,limit 及之后的位置不能使用。
3 int capacity:Buffer 的最大容量,并且在创建后不能更改。
4 int mark:标记,可以在 Buffer 设置一个标记,之后可以通过 reset() 方法返回到列表该标记的位置。
5 long address:堆外内存的地址。
以 ByteBuffer 为例进行说明
| <br>方法<br> | <br>简介<br> |
| <br>public static ByteBuffer allocate(int capacity)<br> | <br>分配大小为 capacity 的非直接缓冲区(单位byte)<br> |
| <br>public static ByteBuffer allocateDirect(int capacity)<br> | <br>分配大小为 capacity 的直接缓冲区(单位byte)<br> |
| <br>public abstract ByteBuffer put(byte b) <br><br>public abstract ByteBuffer put(int index, byte b)<br><br>public final ByteBuffer put(byte[] src)<br><br>public ByteBuffer put(byte[] src, int offset, int length)<br> | <br>向缓冲区中存放数据<br> |
| <br>public abstract byte get()<br><br>public abstract byte get(int index)<br><br>public ByteBuffer get(byte[] dst)<br><br>public ByteBuffer put(byte[] src, int offset, int length)<br> | <br>从缓存区中读取数据<br> |
| <br>public abstract ByteBuffer asReadOnlyBuffer()<br> | <br>将一个 Buffer 转为一个只读 Buffer。之后,不能再对转换后的 Buffer 进行写操作<br> |
| <br>public abstract ByteBuffer slice()<br> | <br>将原 Buffer 从 position 到 limit 之间的部分数据交给一个新的 Buffer 引用。也就是说,此方法返回的 Buffer 引用的数据,是原 Buffer 的一个子集。并且,新的 Buffer 引用和原 Buffer 引用共享相同的数据。<br> |
| <br>public static ByteBuffer wrap(byte[] array)<br> | <br>返回一个内容为 array 的 Buffer。此外,如果修改缓冲区的内容,array 也会随着改变,反之亦然。<br> |
| <br>public final Buffer flip()<br> | <br>将写模式转换成读模式<br> |
| <br>public final Buffer rewind()<br> | <br>用于重复读,具体重现参考源码<br> |
| <br>public final Buffer clear()<br> | <br>清空 Buffer,具体重现参考源码<br> |
| <br>public final Buffer mark()<br> | <br>标记:mark = position,具体重现参考源码<br> |
| <br>public final Buffer reset()<br> | <br>重置:position = mark,具体重现参考源码<br> |
public class NIODemo {
public static void test1() {
ByteBuffer buffer = ByteBuffer.allocate(100);
System.out.println("---allocate----");
System.out.println("position:" + buffer.position()); // position:0
System.out.println("limit:" + buffer.limit()); // limit:100
System.out.println("capacity(定义之后,不会再改变):" + buffer.capacity()); // capacity(定义之后,不会再改变):100
// 向Buffer中存放数据
System.out.println("---put()----");
buffer.put("helloworld".getBytes());
System.out.println("position:" + buffer.position()); // position:10
System.out.println("limit:" + buffer.limit()); // limit:100
// 切换到读模式
System.out.println("---flip()----");
buffer.flip();
System.out.println("position:" + buffer.position()); // position:0
System.out.println("limit:" + buffer.limit()); // limit:10
// 从Buffer中读取数据
System.out.println("---get()----");
byte[] bs = new byte[buffer.limit()];
buffer.get(bs); // 读取数据,同时会后移position
System.out.println("读取到的数据:" + new String(bs)); // 读取到的数据:helloworld
System.out.println("position:" + buffer.position()); // position:10
System.out.println("limit:" + buffer.limit()); // limit:10
System.out.println("----slice()---");
buffer = ByteBuffer.allocate(8);
// buffer:0,1,2,3,4,5,6,7
for (int i = 0; i < buffer.capacity(); i++) {
buffer.put((byte) i);
}
buffer.position(2);
buffer.limit(6);
// sliceBuffer:2,3,4,5;获取从 position 到 limit之间 buffer的引用。
ByteBuffer sliceBuffer = buffer.slice();
// sliceBuffer 与 原Buffer 共享相同的数据;即修改 sliceBuffer 中的数据时,buffer 也会改变。
for (int i = 0; i < sliceBuffer.capacity(); i++) {
byte b = sliceBuffer.get(i);
b += 100;
sliceBuffer.put(i, b);
}
// 测试
System.out.println("当修改了 sliceBuffer 之后,查看 buffer:");
buffer.position(0);
buffer.limit(buffer.capacity());
while (buffer.hasRemaining()) {//{x,x,x,x,x,x} buffer.hasRemaining():判断是否有剩余元素
System.out.print(buffer.get() + ","); // 0,1,102,103,104,105,6,7,
}
System.out.println();
System.out.println("----mark--------");
ByteBuffer buffer2 = ByteBuffer.allocate(100);
buffer2.put("abcdefg".getBytes());
// 在此时的 position 位置处,做一个标记 mark
buffer2.mark();
System.out.println("position:" + buffer2.position()); // position:7
System.out.println("mark:" + buffer2.mark().position()); // mark:7
/*
通过get(byte[] dst, int offset, int length)方法,读取buffer中的“cde”。
注意,此方法可以直接从 Buffer 中的指定位置 offset 开始读取数据,而不需要flip()或rewind()。
*/
buffer2.get(bs, 2, 3);
buffer2.reset(); // 恢复到 position 的位置 7
System.out.println("position:" + buffer2.position()); // position:7
System.out.println("mark:" + buffer2.mark().position()); // mark:7
// 判断缓冲区是否有剩余数据
if (buffer2.hasRemaining()) {
System.out.println("Buffer中的剩余空间数:" + buffer2.remaining()); // Buffer中的剩余空间数:93
}
// 重复读rewind() : 1.postion=0,2.取消mark()
System.out.println("---rewind()----");
buffer2.rewind();
System.out.println("position:" + buffer2.position()); // position:0
// clear()"清空"缓冲区
System.out.println("-------clear()--------");
ByteBuffer buffer3 = ByteBuffer.allocate(100);
buffer3.put("abc".getBytes());
buffer3.clear(); // "清空"缓冲区 :position=0,但数据并没有真正被删除,只是处于废弃状态
System.out.println("position:" + buffer3.position()); // position:0
System.out.println("limit:" + buffer3.limit()); // limit:100
System.out.println("clear()之后,仍然可以获取到Buffer中的数据:" + (char) buffer3.get(1)); // clear()之后,仍然可以获取到Buffer中的数据:b
}
public static void main(String[] args) throws IOException {
test1();
}
}
---allocate----
position:0
limit:100
capacity(定义之后,不会再改变):100
---put()----
position:10
limit:100
---flip()----
position:0
limit:10
---get()----
读取到的数据:helloworld
position:10
limit:10
----slice()---
当修改了sliceBuffer之后,查看buffer:
0,1,102,103,104,105,6,7,
----mark--------
position:7
mark:7
position:7
mark:7
Buffer中的剩余空间数:93
---rewind()----
position:0
-------clear()--------
position:0
limit:100
clear()之后,仍然可以获取到Buffer中的数据:b
package nio;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
import java.nio.charset.CharacterCodingException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class NIODemo {
// Buffer 存储各类型数据
public static void test() throws CharacterCodingException {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.putDouble(3.14159);
buffer.putChar('程');
buffer.flip();
// 必须保证 get 和 put 的顺序一致
System.out.println(buffer.getDouble());
System.out.println(buffer.getChar());
}
public static void main(String[] args) throws IOException {
test();
}
}
3.14159
程
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/chengqiuming/article/details/124829476
内容来源于网络,如有侵权,请联系作者删除!