- 关于 ChatGPT 必看的 10 篇论文
- ChatGPT常见问答
- ChatGPT对接微信
- OpenAI 推出超神 ChatGPT 注册教程来了|Gmail 外国手机短信验证码接码
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
程
我目前正在尝试基于哈希表构建字典。逻辑是:有一个名为 HashTable 的结构,其中包含以下内容: HashFunc HashFunc; PrintFunc PrintEntry; CompareF
如果我有一个指向结构/对象的指针,并且该结构/对象包含另外两个指向其他对象的指针,并且我想删除“包含这两个指针的对象而不破坏它所持有的指针”——我该怎么做这样做吗? 指向对象 A 的指针(包含指向对象
像这样的代码 package main import "fmt" type Hello struct { ID int Raw string } type World []*Hell
我有一个采用以下格式的 CSV: Module, Topic, Sub-topic 它需要能够导入到具有以下格式的 MySQL 数据库中: CREATE TABLE `modules` ( `id
通常我使用类似的东西 copy((uint8_t*)&POD, (uint8_t*)(&POD + 1 ), back_inserter(rawData)); copy((uint8_t*)&PODV
错误 : 联合只能在具有兼容列类型的表上执行。 结构(层:字符串,skyward_number:字符串,skyward_points:字符串)<> 结构(skyward_number:字符串,层:字符
我有一个指向结构的指针数组,我正在尝试使用它们进行 while 循环。我对如何准确初始化它并不完全有信心,但我一直这样做: Entry *newEntry = malloc(sizeof(Entry)
我正在学习 C,我的问题可能很愚蠢,但我很困惑。在这样的函数中: int afunction(somevariables) { if (someconditions)
我现在正在做一项编程作业,我并没有真正完全掌握链接,因为我们还没有涉及它。但是我觉得我需要它来做我想做的事情,因为数组还不够 我创建了一个结构,如下 struct node { float coef;
给定以下代码片段: #include #include #define MAX_SIZE 15 typedef struct{ int touchdowns; int intercepti
struct contact list[3]; int checknullarray() { for(int x=0;x<10;x++) { if(strlen(con
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Empty “for” loop in Facebook ajax what does AJAX call
我刚刚在反射器中浏览了一个文件,并在结构构造函数中看到了这个: this = new Binder.SyntaxNodeOrToken(); 我以前从未见过该术语。有人能解释一下这个赋值在 C# 中的
我经常使用字符串常量,例如: DICT_KEY1 = 'DICT_KEY1' DICT_KEY2 = 'DICT_KEY2' ... 很多时候我不介意实际的文字是什么,只要它们是独一无二的并且对人类读
我是 C 的新手,我不明白为什么下面的代码不起作用: typedef struct{ uint8_t a; uint8_t* b; } test_struct; test_struct
您能否制作一个行为类似于内置类之一的结构,您可以在其中直接分配值而无需调用属性? 前任: RoundedDouble count; count = 5; 而不是使用 RoundedDouble cou
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
在创建嵌套列表时,我认为 R 具有对列表元素有用的命名结构。我有一个列表列表,并希望应用包含在任何列表中的每个向量的函数。 lapply这样做但随后剥离了列表的命名结构。我该怎么办 lapply嵌套列
我正在做一个用于学习目的的个人组织者,我从来没有使用过 XML,所以我不确定我的解决方案是否是最好的。这是我附带的 XML 文件的基本结构:
我是新来的 nosql概念,所以当我开始学习时 PouchDB ,我找到了这个转换表。我的困惑是,如何PouchDB如果可以说我有多个表,是否意味着我需要创建多个数据库?因为根据我在 pouchdb
我是一名优秀的程序员,十分优秀!