Java IO的真面目

1. IO是什么?

       我们都知道IO是input/output 输入输出缩写,也用过IO读取文件。可参考《Java IO之文件读取》。但IO并不只是我从前认识的这么狭隘, 它的身影我们随处可见,从网络读写数据也是IO, 极端的情况对内存读写数据也可以是IO。  IO是对他们的抽象。

 

2.Java 的 I/O 类库的基本架构

File是基于磁盘操作的 I/O 接口,RandomAccessFile是随机存取文件流(既可以读取文件内容,也可以向文件输出数据),

其他还有基于网络操作的 I/O 接口:Socket。

 

字节流byte与字符流char:                                 

1)读写单位不同:字节流以字节(8bit)为单位;字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等);而字符流只能处理字符char类型的数据。

我们知道计算机中的一切都是二进制的字节, 包括你现在正在看到的文章, 但是我们如果直接用InputStream/OutStream来读取这些文本内容, 势必有点麻烦,还得翻译成字符, 所以为了方便API就提供了Reader/Writer 接口, 专门用于处理字符流。其实字符流就是因为数据编码的不同,而有了对字符进行高效操作的流对象。字符流​​​​​​​本质其实就是基于字节流读取时,去查了指定的码表。

 

 如果你还傻傻的分不清什么时候用InputStream, 什么时候用OuputStream,那么我可以教你一个简单的方法: 把自己当成程序, 当你从外边读数据到自己这里就用InputStream,  向外边写数据就用OutputStream。

 

3.磁盘IO工作机制

从磁盘读取文件

        数据在磁盘的唯一最小描述就是文件,也就是说上层应用程序只能通过文件来操作磁盘上的数据,文件也是操作系统和磁盘驱动器交互的一个最小单元。值得注意的是 Java 中通常的 File 并不代表一个真实存在的文件对象,当你通过指定一个路径描述符时,它就会返回一个代表这个路径相关联的一个虚拟对象,这个可能是一个真实存在的文件或者是一个包含多个文件的目录。       

       为何要这样设计?因为大部分情况下,我们并不关心这个文件是否真的存在,而是关心这个文件到底如何操作。只有在真正要读取这个文件时才会去检查这个文件是否存在。 例如 FileInputStream 类都是操作一个文件的接口,注意到上图中在创建一个 FileInputStream 对象时,会创建一个 FileDescriptor 对象,其实这个对象就是真正代表一个存在的文件对象的描述,当我们在操作一个文件对象时可以通过 getFD() 方法获取真正操作的与底层操作系统关联的文件描述。例如可以调用 FileDescriptor.sync() 方法将操作系统缓存中的数据强制刷新到物理磁盘中。  这部分IO工作机制是底层原理,理解起来还需要很多其他知识,暂且不深入分析了。

 

4.你所不知的FilterInputStream 与 装饰者模式

注意是 FilterInputStream 而不是 FileInputStream。

先上图来看下它们之间的结构:FilterInputStream 和 FileInputStream都是InputStream的子类

对于FileInputStream我们已经比较熟悉了,那么这个FilterInputStream又是什么东东,有啥用呢?想了解它,那就得看看它的子类了。

还记得之前的InputStream我们只能读取字节byte吗,DataInputStream比较强大了,用它我们可以直接从stream中读取int,String等类型。(其实去翻看源码,你会发现直接读取int类型,不过是readInt这个方法中,读取出每一个int的4个字节,再进行处理成一个int。) ButtferInputStream使得InputStream具有缓冲的功能。

 

 

    刚好最近在看设计模式,讲到FilterInputStream,就必须要提到一个设计模式:装饰者模式(decorator pattern)。

    装饰者模式,顾名思义,是对原有类进行了一定的装饰,装饰后的类必须和原有的类拥有相同的方法,也可以在原有类的基础上进行扩展。

     这里的装饰者模式通过包含一个原有的Inputstream对象,并且将InputStream原有的方法或直接暴露,或进行装饰后暴露,又或者添加了新的特性,如DataInputStream中的readInt(),BufferedInputStream中的缓存功能。

 

这里还有一个经典的问题,为什么InputStream选择装饰者模式,而非直接继承的方法来扩展?

下图就是继承方式,可以看出InputStream的直接子类中,如FileInputStream,都是定义了输入流的来源,通过文件,或者网络。而FilterInputStream的子类并不是增加了流的来源,而只是改善了流读取方法,比如添加了缓存,直接读取int,String等类型。 所以可以将其简单的理解为只是对IO流的一种装饰。

 

5.总结

本文主要讲的还是磁盘文件读取的FileInputStream/FileOututStream和FilterInputStream,IO的真面目其实还未完成揭开。后续还有IO调优(涉及操作系统知识)和网络 I/O之Socket ,JDBC 驱动程序提供对查询的 SQL 结果的读取和缓存等。还有IO读取过程中的同步和异步,阻塞与非阻塞等都还在等待我们去一步步揭晓。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值