一、IO(同步、阻塞)


1、概述

IO流简单来说就是input和output流,IO流主要是用来处理设备之间的数据传输,Java IO对于数据的操作都是通过流实现的,而java用于操作流的对象都在IO包中。

io流类型 java java中io流分几种_io流类型 java


2、分类

按操作数据分为:字符流(Reader、Writer)和字节流(InputStream、OutputStream)

按流向分:输入流(Reader、InputStream)和输出流(Writer、OutputStream)

io流类型 java java中io流分几种_io流类型 java_02


3、字符流

概述

只用来处理文本数据

数据最常见的表现形式是文件,字符流用来操作文件的子类一般是FileReader和FileWriter

字符流读写文件注意事项:

  • 写入文件必须要用flush()刷新
  • 用完流记得要关闭流
  • 使用流对象要抛出IO异常
  • 定义文件路径时,可以用"/"或者"\"
  • 在创建一个文件时,如果目录下有同名文件将被覆盖
  • 在读取文件时,必须保证该文件已存在,否则抛出异常

字符流的缓冲区

  • 缓冲区的出现是为了提高流的操作效率而出现的
  • 需要被提高效率的流作为参数传递给缓冲区的构造函数
  • 在缓冲区中封装了一个数组,存入数据后一次取出


4、字节流

概述

用来处理媒体数据

字节流读写文件注意事项:

  • 字节流和字符流的基本操作是相同的,但是想要操作媒体流就需要用到字节流
  • 字节流因为操作的是字节,所以可以用来操作媒体文件(媒体文件也是以字节存储的)
  • 输入流(InputStream)、输出流(OutputStream)
  • 字节流操作可以不用刷新流操作
  • InputStream特有方法:int available()(返回文件中的字节个数)

字节流的缓冲区

  • 字节流缓冲区跟字符流缓冲区一样,也是为了提高效率


5、Java Scanner类

Java 5添加了java.util.Scanner类,这是一个用于扫描输入文本的新的实用程序

关于nextInt()、next()、nextLine()的理解

nextInt():只能读取数值,若是格式不对,会抛出java.util.InputMismatchException异常

next():遇见第一个有效字符(非空格,非换行符)时,开始扫描,当遇见第一个分隔符或结束符(空格或换行符)时,结束扫描,获取扫描到的内容

nextLine():可以扫描到一行内容并作为字符串而被捕获到

关于hasNext()、hasNextLine()、hasNextxxx()的理解

就是为了判断输入行中是否还存在xxx的意思

 

二、NIO(同步、非阻塞)

NIO之所以是同步,是因为它的accept/read/write方法的内核I/O操作都会阻塞当前线程

 

io流类型 java java中io流分几种_字节流_03

首先,我们要先了解一下NIO的三个主要组成部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器)


(1)Channel(通道)

Channel(通道):Channel是一个对象,可以通过它读取和写入数据。可以把它看做是IO中的流,不同的是:

  • Channel是双向的,既可以读又可以写,而流是单向的
  • Channel可以进行异步的读写
  • 对Channel的读写必须通过buffer对象

正如上面提到的,所有数据都通过Buffer对象处理,所以,永远不会将字节直接写入到Channel中,相反,是将数据写入到Buffer中;同样,也不会从Channel中读取字节,而是将数据从Channel读入Buffer,再从Buffer获取这个字节。

因为Channel是双向的,所以Channel可以比流更好地反映出底层操作系统的真实情况。特别是在Unix模型中,底层操作系统通常都是双向的。

在Java NIO中的Channel主要有如下几种类型:

  • FileChannel:从文件读取数据的
  • DatagramChannel:读写UDP网络协议数据
  • SocketChannel:读写TCP网络协议数据
  • ServerSocketChannel:可以监听TCP连接


(2)Buffer

Buffer是一个对象,它包含一些要写入或者读到Stream对象的。应用程序不能直接对 Channel 进行读写操作,而必须通过 Buffer 来进行,即 Channel 是通过 Buffer 来读写数据的。

在NIO中,所有的数据都是用Buffer处理的,它是NIO读写数据的中转池。Buffer实质上是一个数组,通常是一个字节数据,但也可以是其他类型的数组。但一个缓冲区不仅仅是一个数组,重要的是它提供了对数据的结构化访问,而且还可以跟踪系统的读写进程。

(三)Selector(选择器对象)

首先需要了解一件事情就是线程上下文切换开销会在高并发时变得很明显,这是同步阻塞方式的低扩展性劣势。

Selector是一个对象,它可以注册到很多个Channel上,监听各个Channel上发生的事件,并且能够根据事件情况决定Channel读写。这样,通过一个线程管理多个Channel,就可以处理大量网络连接了。

selector优点

有了Selector,我们就可以利用一个线程来处理所有的channels。线程之间的切换对操作系统来说代价是很高的,并且每个线程也会占用一定的系统资源。所以,对系统来说使用的线程越少越好。

io流类型 java java中io流分几种_数据_04

NIO 和传统 IO 之间最大的区别是,IO 是面向流的,NIO 是面向缓冲区的。

 

三、AIO(异步、非阻塞)

 

io流类型 java java中io流分几种_字节流_05

AIO是异步IO的缩写,虽然NIO在网络操作中,提供了非阻塞的方法,但是NIO的IO行为还是同步的。对于NIO来说,我们的业务线程是在IO操作准备好时,得到通知,接着就由这个线程自行进行IO操作,IO操作本身是同步的。

但是对AIO来说,则更加进了一步,它不是在IO准备好时再通知线程,而是在IO操作已经完成后,再给线程发出通知。因此AIO是不会阻塞的,此时我们的业务逻辑将变成一个回调函数,等待IO操作完成后,由系统自动触发。

与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 

io流类型 java java中io流分几种_字符流_06

  • 多路复用 IO 比非阻塞 IO 模型的效率高是因为在非阻塞 IO 中,不断地询问 socket 状态时通过用户线程去进行的,而在多路复用 IO 中,轮询每个 socket 状态是内核在进行的,这个效率要比用户线程要高的多。

 

NIO 与 AIO 区别

NIO:会等数据准备好后,再交由应用进行处理,数据的读取/写入过程依然在应用线程中完成,只是将等待的时间剥离到单独的线程中去,节省了数据准备时间,因为多路复用机制,Selector会得到复用,对于那些读写过程时间长的,NIO就不太适合。

AIO:读完(内核内存拷贝到用户内存)了系统再通知应用,使用回调函数,进行业务处理,AIO能够胜任那些重量级,读写过程长的任务。