如果有人再问你 Java IO,把这篇文章砸他头上( 二 )


如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
3.2、字符输出流Writer 输出流的类继承层次如下图所示:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
同样的,输出流根据数据节点类型和处理方式分类,分别可以划分出了若干个子类,如下图:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
不管是 Reader 还是 Writer 类,它们都只定义了读取或写入数据字符的方式,也就是说要么是读要么是写,但是并没有规定数据要写到哪去,写到哪去就是我们后面要讨论的基于磁盘或网络的工作机制 。
四、字节与字符的转化刚刚我们说到,不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符,设计字符的原因是为了程序操作更方便,那么怎么将字符转化成字节或者将字节转化成字符呢?
InputStreamReader 和 OutputStreamWriter 就是转化桥梁 。
4.1、输入流转化过程输入流字符解码相关类结构的转化过程如下图所示:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
从图上可以看到,InputStreamReader 类是字节到字符的转化桥梁,其中StreamDecoder指的是一个解码操作类,Charset指的是字符集 。
InputStream 到 Reader 的过程需要指定编码字符集,否则将采用操作系统默认字符集,很可能会出现乱码问题,StreamDecoder 则是完成字节到字符的解码的实现类 。
打开源码部分,InputStream 到 Reader 转化过程,如下图:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
4.1、输出流转化过程输出流转化过程也是类似,如下图所示:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
通过 OutputStreamWriter 类完成字符到字节的编码过程,由 StreamEncoder 完成编码过程 。
源码部分,Writer 到 OutputStream 转化过程,如下图:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
五、基于磁盘操作的接口前面介绍了 Java I/O 的操作接口,这些接口主要定义了如何操作数据,以及介绍了操作数据格式的方式:字节流和字符流 。
还有一个关键问题就是数据写到何处,其中一个主要的处理方式就是将数据持久化到物理磁盘 。
我们知道数据在磁盘的唯一最小描述就是文件,也就是说上层应用程序只能通过文件来操作磁盘上的数据,文件也是操作系统和磁盘驱动器交互的一个最小单元 。
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
在 Java I/O 体系中,File 类是唯一代表磁盘文件本身的对象 。
File 类定义了一些与平台无关的方法来操作文件,包括检查一个文件是否存在、创建、删除文件、重命名文件、判断文件的读写权限是否存在、设置和查询文件的最近修改时间等等操作 。
值得注意的是 Java 中通常的 File 并不代表一个真实存在的文件对象,当你通过指定一个路径描述符时,它就会返回一个代表这个路径相关联的一个虚拟对象,这个可能是一个真实存在的文件或者是一个包含多个文件的目录 。
例如,读取一个文件内容,程序如下:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
以上面的程序为例,从硬盘中读取一段文本字符,操作流程如下图:
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
我们再来看看源码执行流程 。
当我们传入一个指定的文件名来创建 File 对象,通过 FileReader 来读取文件内容时,会自动创建一个FileInputStream对象来读取文件内容,也就是我们上文中所说的字节流来读取文件 。
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
紧接着,会创建一个FileDescriptor的对象,其实这个对象就是真正代表一个存在的文件对象的描述 。可以通过FileInputStream对象调用getFD()方法获取真正与底层操作系统关联的文件描述 。
如果有人再问你 Java IO,把这篇文章砸他头上

文章插图
 
由于我们需要读取的是字符格式,所以需要 StreamDecoder 类将byte解码为char格式,至于如何从磁盘驱动器上读取一段数据,由操作系统帮我们完成 。
六、基于网络操作的接口继续来说说数据写到何处的另一种处理方式:将数据写入互联网中以供其他电脑能访问 。


推荐阅读