NIO
与 传统IO 的区别
- 传统IO:用的是插管道(单向管道 stream)。可以先了解一下 传统IO Java I/O 原理分析
-
NIO:也是用的插管道(双向管道 channel)。NIO 有非阻塞式的支持,而不是非阻塞式的,而且默认是阻塞式的。其中网络交互支持非阻塞式(默认是阻塞式的),文件交互只能是阻塞式的。
nio
Buffer
在 NIO 中需强制使用 buffer,不用都不行。它的 buffer 可以被操作,操作的是 buffer 本身而不是管道。而且 buffer 不好用,为什么这么说呢,来看一下:
try {
// 传入的参数 name:文件名,mode:模式“r”表示 read,其他还有 rw、rws、rwd
RandomAccessFile file = new RandomAccessFile("./new.txt", "r");
// 管道 channel
FileChannel channel = file.getChannel();
// 获取 buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// buffer 视角,buffer 是内,channel 是外
channel.read(byteBuffer);
// ①
byteBuffer.limit(byteBuffer.position());
byteBuffer.position(0);
// 打印文件中的内容
System.out.println(Charset.defaultCharset().decode(byteBuffer));
// ②
byteBuffer.limit(byteBuffer.capacity());
byteBuffer.position(0);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
首先要了解三个东西:
- capacity:容量。buffer的容量,就是上面代码中的1024
- limit:限制。指的是读或写的最大范围在哪。
- position: 位置。读和写都是用它做指针。读到第几个了,写到第几个了
它们有什么用,到底是什么意思呢?
buffer1
如上图:这是初始状态,position = 0 指向第一个位置,capacity是总容量大小;limit 意思是: position 最多可以达到的大小,初始的时候,limit = capacity,也就是说做多可以读1024个大小的数据(buffer视角输入所以是读)。
这么说可能理解不了,举个例子:
在这里插入图片描述
上图是buffer读了ABCD之后的状态:position会指向4这个位置,意思是读的下一个就是4(buffer视角,输入)。
如果这个时候直接操作 buffer,(内存视角,输入)从buffer读数据到内存并打印,就会有问题。所以必须要设置position和limit,如上面代码中①,先把limit = position,记录限制的大小,然后position = 0。这样才能正常的从buffer读数据到内存中。
下图就是执行了①之后的模型:
buffer3
当读完之后,position 就会和 limit 一样指向4这个位置了。就不画图了。最后在读完之后要重置position 和 limit,就是②所做的事了,buffer的状态就会回到初始状态。
① 和 ② 都是挺常见的操作,buffer 也提供了这样的功能:
// ① 翻页
byteBuffer.flip();
// ② 清除
byteBuffer.clear();
Okio
介绍
- 也是基于插管,而且是单向的
- 输入源:Source
- 输出目标:Sink (水槽,往里面装水用的)
- 也支持 buffer,
- 不强制使用
- 也可以对 buffer 进行操作
使用
简单使用:
try (BufferedSource source = Okio.buffer(Okio.source(new File("./new.txt")))) {
System.out.println(source.readUtf8());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
使用 buffer:
try (BufferedSource source = Okio.buffer(Okio.source(new File("./new.txt")))) {
// 创建 buffer
Buffer buffer = new Buffer();
// 读数据到 buffer(buffer视角,buffer 是内,文件是外)
source.read(buffer, 1024);
// 读数据到内存(内存视角,内存是内,buffer 是外)
System.out.println(buffer.readUtf8Line());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
另外 buffer 还有一个比较灵活比较方便的功能:可以往 buffer 上面插管子 InputStream,OutputStream。这样就可以引入传统 IO,把 Okio 和传统 IO 合起来用。如果老项目老代码用的是传统 IO,而 Okio 也会用到,这样就可以让它们做对接。怎么对接呢?如下:
// Okio 的 buffer
Buffer buffer = new Buffer();
OutputStream outputStream = buffer.outputStream();
InputStream inputStream = buffer.inputStream();
总结
本文主要介绍了NIO,Okio。
NIO和传统IO 的对比,什么情况下才能用非阻塞式。buffer 的原理,该怎么用。
Okio 的介绍和使用。
最后再简单说一下AIO,BIO。
- BIO:就是有的人给传统IO起的名字。B:blocking 阻塞,但是NIO在很多情况下其实也是阻塞式的。。。
- AIO:Asynchronous IO,异步IO。Java7新出的一套带有回调功能的异步IO,跟多线程回调一样用起来比较方便的那种把工作放到后台的IO。
网友评论