Java I/O不迷茫,一文为你导航! (3)

所谓的直接 I/O 的方式就是应用程序直接访问磁盘数据,而不经过操作系统内核数据缓冲区,这样做的目的是减少一次从内核缓冲区到用户程序缓存的数据复制;

这种访问文件的方式通常是在对数据的缓存管理由应用程序实现的数据库管理系统中,如在数据库管理系统中,系统明确地知道应该缓存哪些数据,应该失效哪些数据,还可以对一些热点数据做预加载,提前将热点数据加载到内存,可以加速数据的访问效率,而这些情况如果是交给操作系统进行缓存,那么操作系统将不知道哪些数据是热点数据,哪些是只会访问一次的数据,因为它只是简单的缓存最近一次从磁盘读取的数据而已;

但是直接 I/O 也有负面影响,如果访问的数据不再应用程序缓存之中,那么每次数据都会直接从磁盘进行加载,这种直接加载会非常缓慢,因此直接 I/O 通常与 异步 I/O 进行结合以达到更好的性能;

10.内存映射的方式

Java I/O不迷茫,一文为你导航!

内存映射是指将硬盘上文件的位置与进程逻辑地址空间中一块大小相同的区域一一对应,当要访问内存中一段数据时,转换为访问文件的某一段数据。这种方式的目的同样是减少数据在用户空间和内核空间之间的拷贝操作。当大量数据需要传输的时候,采用内存映射方式去访问文件会获得比较好的效率。

同步和异步访问文件的方式

另外还有两种方式,一种是数据的读取和写入都是同步操作的同步方式,另一种是是当访问数据的线程发出请求之后,线程会接着去处理其他事情,而不是阻塞等待的异步访问方式,但从笔者就《深入分析 Java Web技术内幕》一书中的内容来看,这两种方式更像是对标准访问方式的一个具体说明,是标准访问方式对应的两种不同处理方法,知道就好了...

Java 访问磁盘文件

我们知道数据在磁盘的唯一最小描述就是文件,也就是说上层应用程序只能通过文件来操作磁盘上的数据,文件也是操作系统和磁盘驱动器交互的一个最小单元。值得注意的是 Java 中通常的 File 并不代表一个真实存在的文件对象,当你通过指定一个路径描述符时,它就会返回一个代表这个路径相关联的一个虚拟对象,这个可能是一个真实存在的文件或者是一个包含多个文件的目录。为何要这样设计?因为大部分情况下,我们并不关心这个文件是否真的存在,而是关心这个文件到底如何操作。例如我们手机里通常存了几百个朋友的电话号码,但是我们通常关心的是我有没有这个朋友的电话号码,或者这个电话号码是什么,但是这个电话号码到底能不能打通,我们并不是时时刻刻都去检查,而只有在真正要给他打电话时才会看这个电话能不能用。也就是使用这个电话记录要比打这个电话的次数多很多。

何时真正会要检查一个文件存不存?就是在真正要读取这个文件时,例如 FileInputStream 类都是操作一个文件的接口,注意到在创建一个 FileInputStream 对象时,会创建一个 FileDescriptor 对象,其实这个对象就是真正代表一个存在的文件对象的描述,当我们在操作一个文件对象时可以通过 getFD() 方法获取真正操作的与底层操作系统关联的文件描述。例如可以调用 FileDescriptor.sync() 方法将操作系统缓存中的数据强制刷新到物理磁盘中。

下面以上文读取文件的程序为例,介绍下如何从磁盘读取一段文本字符。如下图所示:

Java I/O不迷茫,一文为你导航!

当传入一个文件路径,将会根据这个路径创建一个 File 对象来标识这个文件,然后将会根据这个 File 对象创建真正读取文件的操作对象,这时将会真正创建一个关联真实存在的磁盘文件的文件描述符 FileDescriptor,通过这个对象可以直接控制这个磁盘文件。由于我们需要读取的是字符格式,所以需要 StreamDecoder 类将 byte 解码为 char 格式,至于如何从磁盘驱动器上读取一段数据,由操作系统帮我们完成。至于操作系统是如何将数据持久化到磁盘以及如何建立数据结构需要根据当前操作系统使用何种文件系统来回答,至于文件系统的相关细节可以参考另外的文章。

参考文章:深入分析 Java I/O 的工作机制
关于这一part,我们只需要了解一下就可以,我也是直接复制就完事儿...

Java 序列化技术

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwsyj.html