IO与NIO

五种IO模型

在网络环境下,通俗的讲,将IO分为两步:等、数据搬迁。如果要想提高IO效率,需要将等的时间降低

五种IO模型包括:

  • 阻塞IO

  • 非阻塞IO

  • 信号驱动IO

  • IO多路转接

  • 异步IO(前四个被称为同步IO)

字节流和字符流

  • 字节流:以字节为单位,每次次读入或读出是8位数据。可以读任何类型数据。

  • 字符流:以字符为单位,每次次读入或读出是16位数据。其只能读取字符类型数据。

输出流和输入流

  • 输出流:从内存读出到文件。只能进行写操作。

  • 输入流:从文件读入到内存。只能进行读操作。

注意:这里的出和入,都是相对于系统内存而言的

节点流和处理流

  • 节点流:直接与数据源相连,读入或读出。

  • 处理流:与节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。

如果是操作二进制文件那我们就使用字节流,如果操作的是文本文件那我们就使用字符流。
尽可能的多使用处理流,这会使我们的代码更加灵活,复用性更好。

随机流:RandomAccessFile

  • 既可以读文件,也可以写文件

  • 可以指定位置读取(应用于多线程下载)

IO与NIO的区别

  • IO是面向流的,NIO是面向缓冲的

  • IO是阻塞的,NIO是非阻塞的

  • IO是单线程的,NIO 是通过选择器来模拟多线程的

NIO之Buffer(缓冲区)

  • 标准的IO编程接口是面向字节流和字符流的。而NIO是面向通道和缓冲区的,数据总是从通道中读到buffer缓冲区内,或者从buffer缓冲区写入到通道中;( NIO中的所有I/O操作都是通过一个通道开始的。)

  • Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方;

  • Java NIO是面向缓存的I/O方法。 将数据读入缓冲器,使用通道进一步处理数据。 在NIO中,使用通道和缓冲区来处理I/O操作。

NIO之Channel(通道)

  • 通道可以读也可以写,流一般来说是单向的(只能读或者写,所以之前我们用流进行IO操作的时候需要分别创建一个输入流和一个输出流)

  • 通道可以异步读写

  • 通道总是基于缓冲区Buffer来读写

  • 通道之间的数据传输

在Java NIO中如果一个channel是FileChannel类型的,那么他可以直接把数据传输到另一个channel

NIO之Channel:Scatter / Gather

Channel 提供了一种被称为 Scatter/Gather 的新功能,也称为本地矢量 I/O。Scatter/Gather 是指在多个缓冲区上实现一个简单的 I/O 操作。正确使用 Scatter / Gather可以明显提高性能

  • Scatter: 从一个Channel读取的信息分散到N个缓冲区中(Buufer)

  • Gather: 将N个Buffer里面内容按照顺序发送到一个Channel

NIO之Selector(选择器)

Selector 一般称为选择器 ,当然你也可以翻译为 多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接

使用Selector的好处在于:使用更少的线程来就可以来处理通道了,相比使用多个线程,避免了线程上下文切换带来的开销

image

I/O多路复用:I/O就是指的我们网络I/O,多路指多个TCP连接(或多个Channel),复用指复用一个或少量线程。串起来理解就是很多个网络I/O复用一个或少量的线程来处理这些连接

I/O复用模式下在第一个阶段大量的连接统统都可以过来直接注册到Selector复用器上面,同时只要单个或者少量的线程来循环处理这些连接事件就可以了,一旦达到“就绪”的条件,就可以立即执行真正的I/O操作。这就是I/O复用与传统的阻塞式I/O最大的不同。也正是I/O复用的精髓所在

白话解读

  • Buffers:网络传输字节存放的地方。

无论是从channel中取,还是向channel中写,都必须以Buffers作为中间存贮格式

  • Socket Channels:Channel是网络连接和buffer之间的数据通道。

每个连接一个channel,就像之前的socket的stream一样

  • Selector:像一个巡警,在一个片区里面不停的巡逻。

一旦发现事件发生,立刻将事件select出来。不过这些事件必须是提前注册在selector上的,select出来的事件打包成SelectionKey。里面包含了事件的发生事件、地点、人物。如果警察不巡逻,每个街道(socket)分配一个警察(thread),那么一个片区有几条街道,就需要几个警察。但现在警察巡逻了,一个巡警(selector)可以管理所有的片区里面的街道(socketchannel)

以上把警察比作线程,街道比作socket或socketchannel,街道上发生的一切比作stream.把巡警比作selector,引起巡警注意的事件比作selectionKey.

从上可以看出,使用NIO可以使用一个线程,就能维护多个持久TCP连接.

文件I/O基石:Path

Java7中文件IO发生了很大的变化,专门引入了很多新的类来取代原来的基于java.io.File的文件IO操作方式

Path path = Paths.get("D:\\XMind\\bcl-java.txt");

拥抱Files类

Java NIO中的Files类(java.nio.file.Files)提供了多种操作文件系统中文件的方法。本节教程将覆盖大部分方法。Files类包含了很多方法,所以如果本文没有提到的你也可以直接查询JavaDoc文档。

java.nio.file.Files类是和java.nio.file.Path相结合使用的

内存映射

这个功能主要是为了提高大文件的读写速度而设计的。内存映射文件(memory-mappedfile)能让你创建和修改那些大到无法读入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问了。将文件的一段区域映射到内存中,比传统的文件处理速度要快很多

涉及到的类:java.nio.MappedByteBufferjava.nio.channels.FileChannel

BIO、NIO和AIO

  • BIO (Blocking I/O):同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成

  • NIO (Non-blocking I/O):同步非阻塞的I/O模型,它支持面向缓冲的,基于通道的I/O操作方法

  • AIO (Asynchronous I/O):异步非阻塞的IO模型,也叫NIO2,异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作

参考文献