文章目录
1. IO流
几乎所有的程序都离不开信息的输入和输出,比如从键盘读取数据,从文件中获取或者向文件中存入数据,在显示器上显示数据。这些情况下都会涉及有关输入/输出的处理。
在Java中,把这些不同类型的输入、输出源抽象为流(Stream),其中输入或输出的数据称为数据流(Data Stream),用统一的接口来表示。
1.1 IO流的分类
数据流是指一组有顺序的、有起点和终点的字节集合。
- 按照流的流向分,可以分为输入流和输出流。注意:这里的输入、输出是针对程序来说的。
- 输出:把程序(内存)中的内容输出到磁盘、光盘等存储设备中。
- 输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
- 按处理数据单位不同分为字节流和字符流。
- 字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码
- 字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。
- 按照流的角色划分为节点流和处理流。
- 节点流:从或向一个特定的地方(节点)读写数据。如FileInputStream。
- 处理流(包装流):是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。
下图是Java IO 流的整体架构图:
1.2 常见IO流
1.2.1 InputStream
java.io 包下所有的字节输入流都继承自 InputStream,并且实现了其中的方法。InputStream 中提供的主要数据操作方法如下:
- int read():从输入流中读取一个字节的二进制数据。
- int read(byte[] b):将多个字节读到数组中,填满整个数组。
- int read(byte[] b, int off, int len):从输入流中读取长度为 len 的数据,从数组 b 中下标为 off 的位置开始放置读入的数据,读完返回读取的字节数。
- void close():关闭数据流。
- int available():返回目前可以从数据流中读取的字节数(但实际的读操作所读得的字节数可能大于该返回值)。
- long skip(long l):跳过数据流中指定数量的字节不读取,返回值表示实际跳过的字节数。
对数据流中字节的读取通常是按从头到尾顺序进行的,如果需要以反方向读取,则需要使用回推(Push Back)操作。 在支持回推操作的数据流中经常用到如下几个方法:
- boolean markSupported():用于测试数据流是否支持回推操作,当一个数据流支持 mark() 和 reset() 方法时,返回 true,否则返回 false。
- void mark(int readlimit):用于标记数据流的当前位置,并划出一个缓冲区,其大小至少为指定参数的大小。
- void reset():将输入流重新定位到对此流最后调用 mark() 方法时的位置。
字节输入流 InputStream 有很多子类,日常开发中,经常使用的一些类见下图:
2.2 字节输出流
与字节输入流类似,java.io 包下所有字节输出流大多是从抽象类 OutputStream 继承而来的。OutputStream 提供的主要数据操作方法:
- void write(int i):将字节 i 写入到数据流中,它只输出所读入参数的最低 8 位,该方法是抽象方法,需要在其输出流子类中加以实现,然后才能使用。
- void write(byte[] b):将数组 b 中的全部 b.length 个字节写入数据流。
- void write(byte[] b, int off, int len):将数组 b 中从下标 off 开始的 len 个字节写入数据流。元素 b[off] 是此操作写入的第一个字节,b[off + len - 1] 是此操作写入的最后一个字节。
- void close():关闭输出流。
- void flush():刷新此输出流并强制写出所有缓冲的输出字节。
为了加快数据传输速度,提高数据输出效率,输出数据流会在提交数据之前把所要输出的数据先暂时保存在内存缓冲区中,然后成批进行输出,每次传输过程都以某特定数据长度为单位进行传输,在这种方式下,数据的末尾一般都会有一部分数据由于数量不够一个批次,而存留在缓冲区里,调用 flush() 方法可以将这部分数据强制提交。
2.2.3 字符输入流
从JDK1.1开始,java.io 包中加入了专门用于字符流处理的类,它们是以Reader和Writer为基础派生的一系列类。
同其他程序设计语言使用ASCII字符集不同,Java使用Unicode字符集来表示字符串和字符。ASCII字符集以一个字节(8bit)表示一个字符,可以认为一个字符就是一个字节(byte)。但Java使用的Unicode是一种大字符集,用两个字节(16bit)来表示一个字符,这时字节与字符就不再相同。为了实现与其他程序语言及不同平台的交互,Java提供一种新的数据流处理方案,称作读者(Reader)和写者(Writer)。
Reader是所有的输入字符流的父类,它是一个抽象类。
CharReader和SringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。BufferedReader很明显是一个装饰器,它和其他子类负责装饰其他Reader对象。FilterReader是所有自定义具体装饰流的父类,其子类PushBackReader对Reader对象进行装饰,会增加一个行号。InputStreamReader是其中最重要的一个,用来在字节输入流和字符输入流之间作为中介,可以将字节输入流转换为字符输入流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。
2.2.4 字符输出流
Writer是所有的输出字符流的父类,它是一个抽象类。
下图是Writer及其一些常用子类的继承图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EIypsNOj-1632818221879)(https://pics2.baidu.com/feed/e7cd7b899e510fb33cba2b1adbfc8093d3430cf4.jpeg?token=d612405b2f4ec2757e3f6f1be3e08ad5&s=23D2836E6C80BF741CF98D090000D0C1)]
CharWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据。BufferedWriter 是一个装饰器为Writer 提供缓冲功能。PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。OutputStreamWriter是其中最重要的一个,用来在字节输出流和字符输出流之间作为中介&#