自学内容网 自学内容网

JAVA基础之I/O

什么是IO流?

IO:输入/输出(Input/Output)
就是JAVA提供的一种用于读写数据的机制,包括输入流和输出流两种。
java中的I/O操作主要是指java.io包下面的对象操作
输入:也叫做数据读取,把将数据读取到内存中,比如读取硬盘中的文本文件。
输出:也叫做写出数据,把数据从内存中写到硬件中。

字节流与字符流

是两种数据的处理类型

字节流

字节流(Byte Streams)
将数据序列化处理为二进制数字形式保存,无论是文本、图片、视频等,都是一个个的字节,这个字节就是java类型中的byte类型。
在javaIO包中操作字节流的顶级父类是这两个

  • InputStream -----> 字节输入流
  • OutputStream -----> 字节输出流

字符流

字符流(Char Streams)
将所有的文件都以字符的形式来存储,用的数据类型是java中的char类型。
在javaIO包中操作字节流的顶级父类是这两个

  • Reader -----> 字符输入流
  • Writer -----> 字符输出流

对比

一般来说,处理文本文件的时候推荐使用字符流,因为他可以更好的处理字符编码问题。
而在处理二进制文件的时候,或者要求更高性能的时候,则推荐使用字节流

IO模型

既然我们上面说了IO是对文件的写入和读取操作,那么和硬件进行交互的时候一定是有一个过程。而程序在这个交互过程中是会进行何种操作,就产生了几种模型。
如图:

在这里插入图片描述

阻塞IO模型

最传统的IO模型,就是在读写过程中,整个线程会进入等待,发生阻塞现象。用户线程交出CPU,进入阻塞状态。当数据就绪之后,内核会将数据拷贝到用户线程,并且返回结果给用户线程,用户线程才会接触block状态。最典型的例子就是 data = socket.read(); 如果没有数据就绪,就会一直阻塞在read()方法里面。

非阻塞IO模型

当用户线程发起一个read操作之后,并不需要等待,而是马上得到一个结果,如果是一个error的话,就是还没有数据,于是再次发送read请求。就是不断的发起read请求,知道某一次请求成功。
与阻塞IO的区别就是,用户线程不会交出CPU,会一直在运行。

while(true){
data = socket.read();
if(data!= error){
//处理数据
break;
}
}

这个有个非常严重的缺点就是,在while循环中,需要不间断的去询问内核数据是否就绪,这样会导致CPU占用率很高。所以一般情况下很少使用while循环这种方式来读取数据。

多路复用IO模型(NIO)

多路复用IO是现在运用比较广泛的一种模型,Java的NIO实际上就是多路复用IO。简单点来说,就是会有一个监听线程不断的去轮询多个socket链接的状态,每当有真正读写事件发生的时候,就分配一个工作线程去处理
也就是说,只需要一个监听线程就可以管理多个socket链接,系统不需要每次都建立或者销毁线程,所以大大减少了CPU的消耗,增加了资源的利用率。我们后面单开一章来详细剖析一下NIO。

信号驱动IO模型

当用户发起一个IO请求操作,会给对应的socket链接注册一个信号函数,然后用户线程会继续执行其他操作。 当内核数据就绪之后,会返回一个信号给用户线程,用户线程接收到这个信号之后,就会再信号函中调用IO来进行实际的读写操作。
通俗来讲,就是先通知一下,等CPU就绪之后告知我,我再去进行读写。

异步IO模型

异步IO模型是最理想的IO模型,在异步IO中,当用户发起read操作之后,立刻就可以开始去做其他事情。 而内核方面,接到了异步read请求(asynchronous read)之后,会立刻返回一个调用请求成功的结果,因此用户线程不会有任何阻塞。然后内核线程等待数据准备完成之后,直接将数据拷贝到用户线程中。这一切完成之后,再发送一个信号给用户线程,告诉他read已经完成。也就是说,用户线程完全不需要管read实际的IO操作如何进行,只需要发起一个请求,再接收到成功信号的时候,整个IO过程已经完成,可以直接在用户线程中使用数据。

听起来与信号驱动有点像,但区别就是信号驱动还是要用户线程再次发起readIO操作,而异步IO完全不需要用户线程调用。内核准备、数据拷贝,这两个阶段都是由内核来完成的,然后告知用户线程就可以了


原文地址:https://blog.csdn.net/weixin_41011482/article/details/142785453

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!