对于任何程序设计语言而言,输入输出(Input/Output)系统都是非常核心的功能。程序运行需要数据,数据的获取往往需要跟外部系统进行通信,外部系统可能是文件、数据库、其他程序、网络、IO设备等等。外部系统比较复杂多变,那么我们有必要通过某种手段进行抽象、屏蔽外部的差异,从而实现更加便捷的编程。
i:输入(Input)指的是:可以让程序从外部系统获得数据(核心含义是“读”,读取外部数据)。
o:输出(Output)指的是:程序输出数据给外部系统从而可以操作外部系统(核心含义是“写”,将数据写出到外部系统)。
流:流是一个抽象、动态的概念,是一连串连续动态的数据集合。
对于输入(Input)流而言,数据源就像水箱,流(stream)就像水管中流动着的水流,程序就是我们最终的用户。我们通过流(A Stream)将数据源(Source)中的数据(information)输送到程序(Program)中。
对于输出(Output)流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目的数据源(dest)中。
常见的IO流构成结构继承关系
IO流中四大抽象类
1、InputStream
此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。 数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类 。
继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit)。
常用方法:
int read():读取一个字节的数据,并将字节的值作为int类型返回(0-255之间的一个值)。如果未读出字节则返回-1(返回值为-1表示读取结束)。
void close():关闭输入流对象,释放相关系统资源。
2、OutputStream
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
常用方法:
void write(int n):向目的地中写入一个字节。
void close():关闭输出流对象,释放相关系统资源。
3、 Reader
Reader用于读取的字符流抽象类,数据单位为字符。
int read(): 读取一个字符的数据,并将字符的值作为int类型返回(0-65535之间的一个值,即Unicode值)。如果未读出字符则返回-1(返回值为-1表示读取结束)。
void close() : 关闭流对象,释放相关系统资源。
4、Writer
Writer用于写入的字符流抽象类,数据单位为字符。
void write(int n): 向输出流中写入一个字符。
void close() : 关闭输出流对象,释放相关系统资源。
IO流中常用类:
FileInputStream:主要用于读取文件内容,每次读取单位是字节,
代码演示
运行结果
可以看到,前面字母读取正常,后边出现了乱码,因为后边是中文文字。每个中文文字占用1个字符=2个字节。而我们打印输出的是一个字节,所以导致了这种情况。
FileReader:主要用于读取文件内容,每次读取1个字符(2个字节),多用于文本的读取
代码演示
运行效果
可以看到,使用FileReader,此时字母被读出来了,汉字也被正常的读出来了。
FileOutputStream:主要用于文件内容的写入,写入单位是字节
代码演示
查看文件写入是否正常;
查看发现,字母正常写入,而汉字显示不正常,这个原因跟上面FileInputStream原因一样。主要是因为汉字占用一个字符(2字节),而我们使用FileOutputStream每次写入是1字节
FileWriter:主要用于文件内容的写入,写入单位是字符,多用于文本文件的写入
代码演示
查看文件写入是否正常;
可以看到,使用FileWriter,汉字也被正常输出
BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter这四个类都是缓存流
缓存流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。 当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。
演示BufferedInputStream、BufferedOutputStream和普通不带缓存的对比
通过两个代码,可以看到,带缓存的流,比普通流处理速度快太多了
DataInputStream和DataOutputStream是处理流提供了可以存取与机器无关的所有Java基础类型数据(如:int、double、String等)的方法。
代码演示:
通过代码演示,可以看到,存在文件中的数据,我们通过普通方法无法直接读取的,但我们程序读取是正常的;
PrintStream打印输出流;打印指定的内容,输出到指定位置,可以是控制台,也可以是文件等等;
代码演示
InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流
System.in是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符流BufferedReader特有的方法readLine(),
但是经过观察会发现在创建BufferedReader的构造方法的参数必须是一个Reader对象,这时候我们的转换流InputStreamReader就派上用场了。
而System.out也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的write(String str)方法,所以我们要使用OutputStreamWriter将字节流转化为字符流。