第7章 IO系统
I/O流:
IO有很多不同的来源和去处,如文件、控制台网络连接等,而且还涉及需求以很多种方式,如顺序读取、随机访问、缓冲、字符、按行读取、按字读取等。
Java8的函数式流相关的类和IO流之间并无关联。
IO流隐藏了实际的IO设备中数据情况的下列细节:
- 字节流用于处理原始的二进制数据。
- 字符流用于处理字符数据。它会自动处理和本地字符集间的相互转换。
- 缓冲区流提升了性能。它通过减少调用本地API的次数,优化了输入和输出。
输入里read()方法,用于从字节数组中读取单个字节或字节数组。
输出里write()方法,用于写入单个字节或字节数组。
各种InputStream类型:
- 字节数组
- 字符串对象
- 文件
- 管道
- 其他流组成的序列,这样可以将这些流合并成单个流。
- 其他源,例如外部网络连接。
类
功能
使用方法
ByteArrayInputStream
使内存中的缓冲区可以充当InputStream
作为一种数据源:通过将其连接到FilterInputStream对象来提供有用的接口
StringBufferInputStream
将字符串转换为InputStream
作为一种数据源:通过将其连接到FilterInputStream对象来提供有用的接口
FileInputStream
用于从一个文件中读取信息
作为一种数据源:通过将其连接到FilterInputStream对象来提供有用的接口
PipedInputStream
用于生成写入到对应的PipedOutputStream中的数据。它实现了管道传输的概念
作为一种多线程形式数据源:通过将其连接到FilterInputStream对象来提供有用的接口
SequenceInputStream
将两个以上的InputStream转换为单个InputStream
作为一种数据源:通过将其连接到FilterInputStream对象来提供有用的接口
FilterInputStream
作为装饰器接口的抽象类,装饰器用来为其他InputStream类提供有用的功能。
各种OutputStream类型:
类
功能
使用方法
ByteArrayOutputStream
在内存创建一块缓冲区,所有发送到流中的数据都被放在该缓冲区
用于指定数据的目的地:通过将其连接到FilterOutputStream对象来提供有用的接口
FileOutputStream
用于向文件发送信息
用于指定数据的目的地:通过将其连接到FilterOutputStram对象来提供有用的接口
PipedOutputStream
向其中写入的任何信息都将自动作为对应的PipedInputStream的输入。实现了管道传输的概念。
用于为多线程制定数据的目的地:通过将其连接到FilterOutputStream对象来提供有用的接口
FilterOutputStream
作为装饰器接口的抽象类,装饰器用来为其他OutputStream类提供有用的功能
各种FilterInputStream类型:
类
功能
使用方法
DataInputStream
与DataOutputStream配合使用,以可移植的方式从流中读取基本类型,int、char、long等
包含用于读取基本类型的全部接口
BufferedInputStream
用于防止在每次需要更多数据时都进行物理上的读取。相等于声明使用缓冲区
这本质上并为提供接口,只是为进程增加缓冲操作而已,需要与接口对象搭配使用
LineNumberInputStream
记录输入流中的行号,可以调用getLineNumber()和setLineNumber(int)
只是增加了行号而已,因此可能需要与借口对象搭配使用
PushbackInputStream
包含一个单字节回退缓冲区,用于将最后读取的字符推回输入流
通常用于编译器的扫描器,一般不会用到
各种FilterOutputStream类型:
类
功能
使用方法
DataOutputStream
与DataInputStream搭配使用没这样就能以可移植的方式向流中写入基本类型
包含用于写入基本类型数据的全部接口
PrintStream
用于生成格式化的输出。DataOutputStream负责处理数据的存储,而PrintStream则负责处理数据的显示
应该作为OutputStream对象的最终包装,可能会经常用到
BufferedOutputStream
用来防止在每次发送数据的时候都发生物理写操作,相当于声明使用缓冲,可以调用flush方法来清空缓冲区
本质上并未提供借口,只是为进程增加缓冲操作而已,需要与借口对象搭配使用
独立的RandomAccessFile:
RandomAccesssFile适合用来处理由大小已知的记录组成的文件,由此可以通过seek方法在各条记录上来回移动,然后读取或者修改记录。文件中各条记录的大小不必相同,只需确定它们的大小以及在文件中的位置即可。
它是一个从零实现的、完全独立的类、有着完全属于自己、大部分是原生的方法,其行为和其他IO类型有本质上的区别。
IO流用法:
- 缓冲输入文件,BufferdReader
- 从内存输入,StringReader
- 格式化的内存输入
- 基本的文件输出
- 存储和恢复数据
- 读写随机访问文件
标准IO:
程序的所有输入都可以来自标准输入,所有输出都可以发送到标准输出,所有错误都可以发送到标准错误。
一个程序的标准输出可以称为另一个程序的标准输入。
新IO系统:
新IO库的目标只有一个:速度。
速度的提升来自于其所使用的更接近于操作系统的IO实现方式的结构:通道和缓冲区。
通道其实很简单:向其传入一个用于读写的Bytebuffer,然后锁住问区域以保证独占式访问。
FileChannel类,在旧IO系统中的类通过getChannel方法得到。
public class IOTest {
public static void main(String[] args) {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
try {
FileInputStream inputStream = new FileInputStream("");
FileChannel channel = inputStream.getChannel();
channel.read(byteBuffer);
channel.write(byteBuffer);
channel.lock();
channel.tryLock();
} catch (IOException e) {
e.printStackTrace();
}
}
}
一旦调用了通道的read方法,就必须在缓冲区上调用flip方法,使缓冲区做好提取字节的准备。并且如果要用缓冲区来做进一步的read操作,就同样需要调用clear方法来让缓冲区为后续的每次read做好准备。
缓冲区中保存着简单的字节,为了将这些字节转换为字符,要么将字节放入的时候进行编码,要么在将他们从缓冲区中读取出来的时候进行解码。
ByteBuffer是由一个8字节的数组包装而成的,随后通过各种不同基本类型的师徒缓冲区将该数组显示出来。
字节序:不同的机器可以使用不同的字节排序方式保存数据。高位优先的方式将最高位的字节放在最低的内存地址,即内存起始地址。低位优先方式将最高位的字节放在最高的内存地址,即内存末尾地址。
内存映射文件:可以创建和修改那些因为太大而无法加载到内存中的文件。
通过在FileChannel上调用tryLock或lock,便可以获得整个文件上的FileLock。