所谓的IO,就是Input/Output,也就是输入和输出。Input是指从外部读入数据到内存,例如读文件,从网络中读取等,为什么要读到内存中才能进行处理呢,因为代码是在内存中运行的,数据也必须读进内存,最终的表示方式,无非是byte数组或者是字符串等等,都必须放到字符串中。

Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在http://java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流),或者抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或者Writer(字符输出流)的子类。

为什么称之为输入/输出流呢,输入/输出流是一种顺序读写数据的模式,数据是单向流动的,就想自来水在水管中的流动,所以称之为IO流。IO流是以byte为最小单位的,例如从硬盘中读入一个文件包含六个字符,就相当于读入了六个字节的数据。

从java代码看,Input的是从外部例如从硬盘上的某个文件把内容读到内存 并且以java提供的某种数据形式来表示例如Byte数组,这样后续的代码才能处理文件内容。

而Output正好相反,它是把数据从内存输出到外部,例如写文件,输出到网络等。从代码来看,output的实质就是把java表示的数据格式输出到某处例如硬盘上的文件。

对于字符不是单字节的ASCII,java提供了Reader和Writer来表示字符流,字符流传输的最小单位是char,字符流输出的byte取决于编码方式,例如我们把一个char数组“hi,你好”用字符流写入文件并使用utf8,则最终文件占八个字节。Reader和Writer本质是一个能编解码的InputStream/OuputStream。

当我们使用Reader/Writer时,数据元是字节,但我们读入/写出的数据是char类型的字符,原因是Reader/Writer内部对读入/写出的Byte使用了编码,使用了InputStream/OutputStream来进行读入/写出的数据和原始的二进制数据是一摸一样的,都是Byte数组。但我们可以对二的进制Byte数组按照某种编码方式,转化为字符串,也可以达到和Reader/Writer一样的效果。

那么应该使用InputStream/OutputStream还是Reader/Writer呢,这取决于具体的使用场景,如果数据源不是文本,那么只能使用IS,而如果是文本,那么Reader就会方便许多。

IO其实分为两种,一种是同步IO,一种是异步IO。同步io就是我们通常使用的http://java.io包,在读写IO代码时需要等待数据返回后才会继续执行后续代码,代码的编写简单但是CPU的执行效率更低。而异步IO是java.nio包,在读写IO时仅发出请求,然后立刻执行后序代码,代码的编写复杂,但是CPU得执行效率也更高。