吃透Java IO:字节流、字符流、缓冲流

前言有人曾问fastjson的作者(阿里技术专家高铁):“你开发fastjson , 没得到什么好处 , 反而挨了骂背了锅 , 这种事情你为什么要做呢?”
高铁答道:“因为热爱本身 , 就是奖励啊!”
这个回答顿时触动了我 。 想想自己 , 又何尝不是如此 。
吃透Java IO:字节流、字符流、缓冲流文章插图
IO流是Java中的一个重要构成部分 , 也是我们经常打交道的 。
下面几个问题(问题还会继续补充) , 如果你能对答如流 , 那么恭喜你 , IO知识掌握得很好 , 可以立即关闭文章 。 反之 , 你可以在后面得文章中寻找答案 。

  1. Java IO流有什么特点?
  2. Java IO流分为几种类型?
  3. 字节流和字符流的关系与区别?
  4. 字符流是否使用了缓冲?
  5. 缓冲流的效率一定高吗?为什么?
  6. 缓冲流体现了Java中的哪种设计模式思想?
  7. 为什么要实现序列化?如何实现序列化?
  8. 序列化数据后 , 再次修改类文件 , 读取数据会出问题 , 如何解决呢?
1 初识Java IOIO , 即in和out , 也就是输入和输出 , 指应用程序和外部设备之间的数据传递 , 常见的外部设备包括文件、管道、网络连接 。
Java 中是通过流处理IO 的 , 那么什么是流?
流(Stream) , 是一个抽象的概念 , 是指一连串的数据(字符或字节) , 是以先进先出的方式发送信息的通道 。
当程序需要读取数据的时候 , 就会开启一个通向数据源的流 , 这个数据源可以是文件 , 内存 , 或是网络连接 。 类似的 , 当程序需要写入数据的时候 , 就会开启一个通向目的地的流 。 这时候你就可以想象数据好像在这其中“流”动一样 。
一般来说关于流的特性有下面几点:
  1. 先进先出:最先写入输出流的数据最先被输入流读取到 。
  2. 顺序存取:可以一个接一个地往流中写入一串字节 , 读出时也将按写入顺序读取一串字节 , 不能随机访问中间的数据 。 (RandomAccessFile除外)
  3. 只读或只写:每个流只能是输入流或输出流的一种 , 不能同时具备两个功能 , 输入流只能进行读操作 , 对输出流只能进行写操作 。 在一个数据传输通道中 , 如果既要写入数据 , 又要读取数据 , 则要分别提供两个流 。
1.1 IO流分类IO流主要的分类方式有以下3种:
  1. 按数据流的方向:输入流、输出流
  2. 按处理数据单位:字节流、字符流
  3. 按功能:节点流、处理流

吃透Java IO:字节流、字符流、缓冲流文章插图
1、输入流与输出流
输入与输出是相对于应用程序而言的 , 比如文件读写 , 读取文件是输入流 , 写文件是输出流 , 这点很容易搞反 。
吃透Java IO:字节流、字符流、缓冲流文章插图
2、字节流与字符流
字节流和字符流的用法几乎完成全一样 , 区别在于字节流和字符流所操作的数据单元不同 , 字节流操作的单元是数据单元是8位的字节 , 字符流操作的是数据单元为16位的字符 。
为什么要有字符流?
Java中字符是采用Unicode标准 , Unicode 编码中 , 一个英文为一个字节 , 一个中文为两个字节 。
吃透Java IO:字节流、字符流、缓冲流文章插图
而在UTF-8编码中 , 一个中文字符是3个字节 。 例如下面图中 , “云深不知处”5个中文对应的是15个字节:-28-70-111-26-73-79-28-72-115-25-97-91-27-92-124
吃透Java IO:字节流、字符流、缓冲流文章插图
那么问题来了 , 如果使用字节流处理中文 , 如果一次读写一个字符对应的字节数就不会有问题 , 一旦将一个字符对应的字节分裂开来 , 就会出现乱码了 。 为了更方便地处理中文这些字符 , Java就推出了字符流 。
字节流和字符流的其他区别:
  1. 字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件 。 字符流一般用于处理纯文本类型的文件 , 如TXT文件等 , 但不能处理图像视频等非文本文件 。 用一句话说就是:字节流可以处理一切文件 , 而字符流只能处理纯文本文件 。
  2. 字节流本身没有缓冲区 , 缓冲字节流相对于字节流 , 效率提升非常高 。 而字符流本身就带有缓冲区 , 缓冲字符流相对于字符流效率提升就不是那么大了 。 详见文末效率对比 。
以写文件为例 , 我们查看字符流的源码 , 发现确实有利用到缓冲区: