四种常见的IO模型
1、同步阻塞IO
首先,解释一下阻塞与非阻塞。
阻塞 IO 指的是需要内核 IO 操作彻底完成后才返回到用户空间执行用户程序的操作指令。“阻塞”指的是用户程序(发起IO请求的进程或者线程)的执行状态。可以说传统的 IO 模型都是阻塞 IO 模型,并且在 Java 中默认创建的 socket 都属于阻塞 IO 模型。
其次,解释一下同步与异步。简单来说,可以将同步与异步看成发起 IO 请求的两种方式。同步 IO 是指用户空间(进程或者线程)是主动发起 IO 请求的一方,系统内核是被动接收方。异步 IO 则反过来,系统内核是主动发起 IO 请求的一方,用户空间是被动接收方。
同步阻塞 IO(Blocking IO)指的是用户空间(或者线程)主动发起,需要等待内核 IO 操作彻底完成后才返回到用户空间的 IO 操作。在 IO 操作过程中,发起 IO 请求的用户进程(或者线程)处于阻塞状态。
2、同步非阻塞IO
非阻塞IO(Non-Blocking IO,NIO)指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间去执行后续的指令,即发起 IO 请求的用户进程(或者线程)处于非阻塞状态,与此同时,内核会立即返回给用户一个 IO 状态值。
阻塞和非阻塞的区别是什么呢?阻塞是指用户进程(或者线程)一直在等待,而不能做别的事情;非阻塞是指用户进程(或者线程)获得内核返回的状态值就返回自己的空间,可以去做别的事情。
在 Java 中,非阻塞 IO 的 socket 被设置为 NONBLOCK 模式。
同步非阻塞 IO 指的是用户进程主动发起,不需要等待内核IO操作彻底完成就能立即返回用户空间的IO操作。在 IO 操作过程中,发起 IO 请求的用户进程(或者线程)处于非阻塞状态。
同步非阻塞 IO 也可以简称为 NIO,但是它不是 Java 编程中的 NIO。Java 编程中的 NIO(New IO)类库组件所归属的不是基础 IO 模型中的 NIO 模型,而是 IO 多路复用模型。
3、IO多路复用
为了提高性能,操作系统引入了一种新的系统调用,专门用于查询 IO 文件描述符(含 socket 连接)的就绪状态。在 Linux 系统中,新的系统调用为 select/epoll 系统调用。通过该系统调用,一个用户进程(或者线程)可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核就能够将文件描述符的就绪状态返回给用户进程(或者线程),用户空间可以根据文件描述符的就绪状态进行相应的 IO 系统调用。
IO 多路复用(IO Multiplexing)属于一种经典的 Reactor 模式实现,有时也称为异步阻塞 IO,Java 中的 Selector 属于这种模型。
4、异步IO
异步 IO(Asynchronous IO,AIO)指的是用户空间的线程变成被动接收者,而内核空间成为主动调用者。在异步 IO 模型中,当用户线程收到通知时,数据已经被内核读取完毕并放在了用户缓冲区内,内核在 IO 完成后通知用户线程直接使用即可。
异步 IO 类似于 Java 中典型的回调模式,用户进程(或者线程)向内核空间注册了各种 IO 事件的回调函数,由内核去主动调用。
接下来对以上 4 种常见的 IO 模型进行详细的介绍。
File类的常用方法
File类用于封装一个路径,该路径可以是从系统盘符开始的绝对路径,也可以是相对于当前目录而言的相对路径
File类内部封装的路径可以指向一个文件,也可以指向一个目录,在使用File类操作文件或者目录之前,首先得创建一个File对象
遍历目录下的文件
isDirectory()方法判断路径指向的目录是否存在。
list()方法,获得一个String类型的数组,数组中包含这个目录下所有的文件的文件名。
list(FilenameFilter)方法获取指定类型的文件。
删除文件及目录
File类delete()方法删除文件,但无法删除目录
要想删除文件及目录,需要通过递归的方式将整个目录以及其中的文件全部删除。
RandomAccesseFile
RandomAccessFile可以将文件以只读或者读写的方式打开,具体使用哪种方式取决于创建它所采用的构造方法
例:使用RandomAccessFile类实现记录软件试用次数的过程
字符编码
字符码表
字符码表是一种可以方便计算机识别的特定字符集,它是将每一个字符和一个唯一的数字对应而形成的一张表。
字符编码和解码
把字符串转换成计算机识别的字节序列称为编码
把字节序列转换为普通人能看懂的明文字符串称为解码
尝试使用ISO8859-1码表对GBK编码的数组进行解码时,出现了四个问号,这是由编码和解码时使用的码表不一致所造成的乱码问题。
字符传输
乱码是由于编码和解码方式不一致导致的
通过构造方法InputStreamReader(InputStream in,String charsetName)和OutputStreamReader(OutputStream in,String charsetName)创建流对象时,可以对需要读写的数据指定编码格式