NIO 原理分析、Okio 简单使用

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。

猜你喜欢

转载自juejin.im/post/5e134697f265da5d2076f49a