IO简介
摘抄了下维基百科对IO的定义,Input/Output,输入和输出,通常指数据在存储器或者其他周边设备之间的输出和输入,输入是系统接收到信号或者数据,输出则是从系统发送的信号或数据。
Java IO 读写原理
Java中文件IO是Java层面上的应用开发,Socket是linux底层开发,都属于输入Input和输出Output的处理,简称IO读写。在原理上和处理流过程一致,区别仅仅是参数的不同。
对程序进行IO操作,基本上会用到read&write两大系统调用。可能不同的操作系统,名称不一样,功能却是一样的。
read系统调用,是将数据从内核缓冲区中复制到进程缓冲区,而write系统调用,是将数据从进程缓冲区复制到内核缓冲区。这两个系统调用,都不会负责数据在内核缓冲区和磁盘之间的交换。底层的读写,是由操作系统kernel内核完成的。
关于用户进程缓冲区和内核缓冲区的概念,可以参考一下这篇文档, 这边简述一下这两个概念:
- 用户进程缓冲区
用户进程通过调用访问系统资源的时候,需要切换到内核态,切换到内核态一般需要进行进程上下文的切换,这种切换需要消耗大量的时间, 用户缓冲区的目的是为了减少系统调用的次数,从而降低操作系统在用户态和核心态切换耗费的时间。
- 内核进程缓冲区
当一个用户进程要从磁盘读取数据时,内核一般不会直接读取磁盘,而是将内核缓冲区中的数据复制到进程缓冲区中。但若是内核缓冲区中没有数据,内核会把对数据块的请求,加入到请求队列,然后把进程挂起,为其它进程提供服务。
等到数据已经读取到内核缓冲区时,把内核缓冲区中的数据读取到用户进程中,才会通知进程。
read是把数据从内核缓冲区复制到进程缓冲区。write是把进程缓冲区复制到内核缓冲区。write并不一定导致内核的写动作,比如os可能会把内核缓冲区的数据积累到一定量后,再一次写入。这也就是为什么断电有时会导致数据丢失。所以说内核缓冲区,是为了在OS级别,提高磁盘IO效率,优化磁盘写操作。
下图描述了每个进程4G地址空间的分配情况,具体内容请参考Linux 内核空间与用户空间
我们画个简图描述一下操作系统进行IO读写的过程是如何的
1、运行的java程序可能需要从磁盘中读取一些文件信息
2、调用java语言的api发起这次请求
3、api底层从用户缓冲区中去读取数据
4、如果用户缓冲区中有值,直接读取数据,如果没有缓存,则会发起系统read&write,去检查内核缓冲区是否有值
5、内核缓冲区没有值,业务进程就会挂起等待
6、内核缓冲区会去IO设备里面去读取数据,直到有数据能被读取