IO
大约 5 分钟
IO
IO 流在 Java 中分为输入流和输出流
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
字节流
- InputStream: 用于从源头(通常是文件)读取数据(字节信息)到内存中
- read()
- FileInputStream : 可直接指定文件路径
- BufferedInputStream: 字节缓冲输入流,new BufferedInputStream(new FileInputStream("input.txt"))
- DataInputStream: 读取指定类型数据,new DataInputStream(new FileInputStream("input.txt"))
- ObjectInputStream: 读取 Java 对象(反序列化)new ObjectInputStream(new FileInputStream("object.file"))
- read()
- OutputStream: 用于将数据(字节信息)写入到目的地(通常是文件)
- write(byte b[ ])
- FileOutputStream: 可直接指定文件路径
- BufferedOutputStream
- DataOutputStream:
- writeByte
- writeBoolean
- ObjectInputStream: 对象写入到输出流(ObjectOutputStream,序列化)
- write(byte b[ ])
字符流
字节 vs 字符
- 字节流
- 字节(Byte)是计算机信息存储的最小单位,所以字节流可以操作所有类型的文件,每次操作1个字节;
- 字符流
- 字符流只能用操作纯文本数据,每次操作一个字符(两个字节);
- 字符流涉及到了缓冲区,所以在使用字符流进行写数据时,需要调用flush()或close()方法进行刷新才能将数据写入文件中。
- 调用flush()刷新后可以继续写数据
- 调用close()相当于刷新后关闭流,不能继续写数据。
- 字符流涉及到编码、解码工作
- 字符流默认采用的是 Unicode 编码,我们可以通过构造方法自定义编码。
常用字符编码
- utf8 :英文占 1 字节,中文占 3 字节
- unicode:任何字符都占 2 个字节
- gbk:英文占 1 字节,中文占 2 字节
字符流
- Reader(字符输入流)
- 用于从源头(通常是文件)读取数据(字符信息)到内存中
- java.io.Reader抽象类是所有字符输入流的父类。
- InputStreamReader:
- 字节流转换为字符流的桥梁
- 子类 FileReader 是基于该基础上的封装,可以直接操作字符文件。
- FileReader extends InputStreamReader
- new FileReader("input.txt");
- Writer(字符输出流)
- 用于将数据(字符信息)写入到目的地(通常是文件)
- java.io.Writer抽象类是所有字符输出流的父类。
- OutputStreamWriter:
- 字符流转换为字节流的桥梁
- 子类 FileWriter 是基于该基础上的封装,可以直接将字符写入到文件。
- FileWriter extends OutputStreamWriter
- new FileWriter("output.txt")
字节缓冲流
- IO 操作是很消耗性能的,缓冲流将数据加载至缓冲区,一次性读取/写入多个字节,从而避免频繁的 IO 操作,提高流的传输效率。
- 字节缓冲流这里采用了装饰器模式来增强 InputStream 和OutputStream子类对象的功能。
- 例:可以通过 BufferedInputStream(字节缓冲输入流)来增强 FileInputStream 的功能。
- 字节缓冲流会先将读取到的字节存放在缓存区
- 缓冲区实际就是一个字节数组
- 缓冲区的大小默认为 8192 字节
- BufferedInputStream(字节缓冲输入流)
- BufferedOutputStream(字节缓冲输出流)
字符缓冲流
- BufferedReader (字符缓冲输入流)
- BufferedWriter(字符缓冲输出流)
- 类似于 BufferedInputStream(字节缓冲输入流)和BufferedOutputStream(字节缓冲输入流)内部都维护了一个字节数组作为缓冲区。不过,前者主要是用来操作字符信息。
打印流
- System.out 实际是用于获取一个 PrintStream 对象
- print方法实际调用的是 PrintStream 对象的 write 方法
- PrintStream 是 OutputStream 的子类,PrintWriter 是 Writer 的子类。
随机访问流
- 指的是支持随意跳转到文件的任意位置进行读写的 RandomAccessFile
- RandomAccessFile(File file, String mode)
- this(file, mode, false) , 默认值 openAndDelete 为 false
- RandomAccessFile(File file, String mode, boolean openAndDelete)
IO 设计模式
装饰器模式
- 可以在不改变原有对象的情况下拓展其功能。
- 通过组合替代继承来扩展原始类的功能,在一些继承关系比较复杂的场景(IO 这一场景各种类的继承关系就比较复杂)更加实用。
- 对原始类嵌套使用多个装饰器
- 例:通过 BufferedInputStream(字节缓冲输入流)来增强 FileInputStream 的功能。
- BufferedInputStream(InputStream in)
- new BufferedInputStream(new FileInputStream("input.txt"))
适配器模式?
工厂模式?
IO 模型
- IO 模型一共有 5 种:同步阻塞 I/O、同步非阻塞 I/O、I/O 多路复用、信号驱动 I/O 和异步 I/O。
Java IO 模型
- BIO (Blocking I/O)
- 同步阻塞 IO 模型
- 应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。
- NIO (Non-blocking/New I/O)
- Java 1.4 中引入
- Java 中的 NIO 属于同步非阻塞 IO 模型
- 通过轮询操作,避免了一直阻塞。
- Java 中的 NIO 可以看作是 I/O 多路复用模型。
- 先发起 select 调用,内核数据是否准备就绪
- read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。
- N 可以理解为 Non-blocking,不单纯是 New。它是支持面向缓冲的,基于通道的 I/O 操作方法。
- 高负载、高并发的(网络)应用,应使用 NIO 。可以使用少量的线程来处理多个连接。
- 非阻塞、面向缓冲、基于通道的 I/O
- AIO (Asynchronous I/O)
- NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。
- 基于事件和回调机制实现
- 应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。