IO流简介
IO(Input Output)用于实现对数据的输入与输出操作,Java把不同的输入/输出源(键盘、文件、网络等)抽象表述为流(Stream)。流是从起源到接收的有序数据,有了它程序就可以采用同一方式访问不同的输入/输出源。
- 按照数据流向,可以将流分为输入流和输出流,其中输入流只能读取数据、不能写入数据,而输出流只能写入数据、不能读取数据。
- 按照数据类型,可以将流分为字节流和字符流,其中字节流操作的数据单元是8位的字节,而字符流操作的数据单元是16位的字符。
- 按照处理功能,可以将流分为节点流和处理流,其中节点流可以直接从/向一个特定的IO设备(磁盘、网络等)读/写数据,也称为低级流,而处理流是对节点流的连接或封装,用于简化数据读/写功能或提高效率,也称为高级流。
Java提供了大量的类来支持IO操作,下表整理了其中比较常用的一些类。其中,第一行是抽象父类,其他所有的类都继承自它们。
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象父类 | InputStream | OutputStream | Reader | Writer |
文件流(节点流) | FileInputStream | FileOutputStream | FileReader | FileWriter |
数组流(节点流) | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
管道流(节点流) | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
字符串流(节点流) | StringReader | StringWriter | ||
缓冲流(处理流) | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流(处理流) | InputStreamReader | OutputStreamWriter | ||
对象流(处理流) | ObjectInputStream | ObjectOutputStream | ||
打印流(处理流) | PrintStream | PrintWriter | ||
推回输入流(处理流) | PushbackInputStream | PushbackReader | ||
特殊流(处理流) | DataInputStream | DataOutputStream |
根据命名理解各个流的作用:
- 以File开头的文件流用于访问文件
- 以ByteArray/CharArray开头的流用于访问内存中的数组
- 以Piped开头的管道流用于访问管道,实现进程之间的通信
- 以String开头的流用于访问内存中的字符串
- 以Buffered开头的缓冲流,用于在读写数据时对数据进行缓存,以减少IO次数
- InputStreamReader、InputStreamWriter是转换流,用于将字节流转换为字符流
- 以Object开头的流是对象流,用于实现对象的序列化
- 以Print开头的流是打印流,用于简化打印操作
- 以Pushback开头的流是推回输入流,用于将已读入的数据推回到缓冲区,从而实现再次读取
- 以Data开头的流是特殊流,用于读写Java基本类型的数据
Java的序列化与反序列化
序列化与反序列化的简介
序列化机制可以将对象转换成字节序列,这些字节序列可以保存在磁盘上,也可以在网络中传输,并允许程序将这些字节序列再次恢复成原来的对象。其中,对象的序列化(Serialize),是指将一个Java对象写入IO流中,对象的反序列化(Deserialize),则是指从IO流中恢复该Java对象。
若对象要支持序列化机制,则它的类需要实现Serializable接口,该接口是一个标记接口,它没有提供任何方法,只是标明该类是可以序列化的,Java的很多类已经实现了Serializable接口,如包装类、String、Date等。
若要实现序列化,则需要使用对象流ObjectInputStream和ObjectOutputStream。其中,在序列化时需要调用ObjectOutputStream对象的writeObject()方法,以输出对象序列。在反序列化时需要调用ObjectInputStream对象的readObject()方法,将对象序列恢复为对象。
serialVersionUID变量
serialVersionUID代表序列化的版本,通过定义类的序列化版本,在反序列化时,只要对象中所存的版本和当前类的版本一致,就允许做恢复数据的操作,否则将会抛出序列化版本不一致的错误。如果不定义序列化版本,在反序列化时可能出现冲突的情况,例如:
- 创建该类的实例,并将这个实例序列化,保存在磁盘上;
- 升级这个类,例如增加、删除、修改这个类的成员变量;
- 反序列化该类的实例,即从磁盘上恢复修改之前保存的数据。
在第3步恢复数据的时候,当前的类已经和序列化的数据的格式产生了冲突,可能会发生各种意想不到的问题。增加了序列化版本之后,在这种情况下则可以抛出异常,以提示这种矛盾的存在,提高数据的安全性。
本文编写于2021-07-31,日后的学习和工作会继续完善IO类的具体使用