- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
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
程
我花了相当多的时间尝试优化文件哈希算法,以尽可能地提高性能。 查看我之前的 SO 主题: Get File Hash Performance/Optimization FileChannel Byte
我不太明白它们之间有什么不同,所以我对这两个包有一些疑问。 在 Google 上浏览了一下之后,似乎 Oracle 决定使用更新和增强的 NIO.2 包来更新 NIO 包,作为 JDK7 版本的一部分
在 Java 1.4 之前,通过在不同的输入流/输出流之间移动字节来处理文件是常见的做法。 自 Java 1.4 起,其中 NIO已添加,建议使用 Channels 执行相同操作。 与 NIO2在 J
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我需要重写一些应该在 Java 6 VM 上运行的 Java 7 文件 IO 代码。 该实现使用了方便的 Java 7 功能,例如自动关闭、Paths 和 Files。 更具体地说,我需要处理像 /t
当我查看java中Scanner的源代码时,我发现一些让我困惑的事情 import java.nio.file.Path; import java.nio.*; 它们之间有什么区别,为什么它们不直接导
我的 Java 代码中几乎所有文件 I/O 操作都使用 java.nio.*。然而,在今天调试一段代码时,我注意到调试器 (Intellij IDEA 14) 显示了以下关于 java.nio.fil
奇怪的是,我无法在 Google 中找到 NIO.2 异步 IO 性能与通过 java.nio.channels.Selector 使用 NIO 的多路复用 IO 的明确答案。 所以,我的问题是:NI
我是初级 Java 程序员。 今天,我练习了如何在 java 中复制文件并尝试按照本教程进行操作 http://www.journaldev.com/861/4-ways-to-copy-file-i
我有一个指向绝对路径的 java.nio.Path: /home/user/project/resources/configuration.xml 我有第二个 java.nio.Path 指向项目的根
我开始使用java.nio.*,现在我想知道:为什么java.nio.Paths.get(..)不使用java.nio.Path 对象作为输入? 现在我总是做这样的事情: final Path bas
我是新手,正在学习 Java。我尝试在 Netbeans 7 中运行以下应用程序。 import java.io.*; import java.nio.file.*; import java.nio.
我的 Java 程序(见下文)有时会在 java.nio.File.move() 方法执行中因 java.nio.file.AccessDeniedException 崩溃。 我不明白为什么会抛出这个
所以我在这里阅读我最喜欢的软件模式书籍之一(面向模式的软件架构 - 并发和网络对象的模式),特别是关于 Proactor/Reactor 异步 IO 模式的部分。我可以看到通过使用可选 channel
我有一个方法如下,它已经正常运行了很长时间: private String loadFromFile(){ RandomAccessFile inFile = null; FileCh
我在 IntellijIDEA Community Edition 2017.3 版本中收到以下错误。该项目使用java版本“1.8.0-ea”。请给我一些解决问题的想法 Error:Internal
一 点睛 在 scatter-and-gather 场景下,可以将数据写入多个 Buffer 中。在 NIO 中,也能够同时操作多个缓冲区。在很多 Channel 实现类中,都提供了多个重载的 rea
I/O简介 在 Java 编程中,直到最近一直使用 流 的方式完成 I/O。所有 I/O 都被视为单个的字节的移动,通过一个称为 Stream 的对象一次移动一个字节。流 I/O 用于与外部世界接
一 点睛 给某一个文件加锁,防止并发访问时引起的数据不安全。 在 JUC 中,可以使用 synchronized、Lock 给共享的资源加锁,或者使用 volatile、CAS 算法等防止并发冲突。在
一 点睛 给某一个文件加锁,防止并发访问时引起的数据不安全。 在 JUC 中,可以使用 synchronized、Lock 给共享的资源加锁,或者使用 volatile、CAS 算法等防止并发冲突。在
我是一名优秀的程序员,十分优秀!