java 字节流入门(读文件)

本文探讨了Java中使用RandomAccessFile进行文件读取时应注意的细节,特别是如何确保完整读取所需数据,并介绍了readFully方法的优势及应用场景。

       文件系列往期文章:

       java 字节流入门(文件流)

       java 字节流入门(内存数组流)

       java 字节流入门(内存数组流->文件流)

       从磁盘到内存的流程大体介绍完了,本文主要介绍读文件中的坑,在实际系统中,如果不注意这些小坑,有可能导致系统挂掉。

       写文件基本是单线程顺序写的,用 FileOutputStream 就可以了。但是读文件一般不是顺序读的,为了实现想读哪里读哪里的功能,通常需要 RandomAccessFile。

       在我们读文件之前,首先要知道数据起始位置(offset)和长度(length),这样才能使用 RandomAccessFile 的 seek方法移动到数据起始位置,然后将数据读出来。

       基本过程就是这样的,很简单:

aae4cbf60b47f3340873048e8f0b12dd.png

       上面这段代码看起来挺完整的,但是,缺少了一个重要环节,验证。当你交给一个人做一件事之后,要验证他是否完成,以及完成的怎么样。这里也一样。

       RandomAccessFile 的 read(byte b[]) 方法的定义是这样的(去掉了不重要的doc):读取 b.length 个字节,放到 b 中,并返回一共读取了多少个字节;当到达文件末尾,没有数据可读时,返回 -1。

fd438e26c5b0b62b96c86f0204a83691.png

       在程序中每一个细节都是需要注意的。那么,这里为什么要有返回值?

       读多少数据是我告诉这个方法的,它又返回给我,这不是有病吗?不是。因为能读出来多少数据是不确定的,即这个方法不能保证一次调用肯定能读出来 b.length 个字节的数据。其中一个原因是:文件没有这么多字节可读。

       不确定还有没有其他原因,我在一个4G的文件中单线程随机读取1G以内的数据4万次,返回的值都和要求读取的值一样,但是一个 up to 应该不能为这个方法打包票,即还有其他原因会导致方法无法读取到需要的数据。这里是猜测,暂且命名 乔老师猜想

       我为什么要提这个 up to 呢,因为 InputStream 的 read(byte b[]) 的说明更过分:

6dfdd5d4e846ffa8fa5de83dd7835a24.png

       第一句说  Reads some number of bytes from the input stream 6350d2495f6ce519355ef88663f9842c.png 这是什么doc,搞笑呢?但是这就是这个方法的本来面目。它确实无法保证能读到你想要的完整数据。

       但是,有一点是可以确定的,那就是  the total number of bytes read into the buffer 。你可以检查是否读到了完整的数据。

       而实际系统中:你必须检查是否读到了完整的数据。否则你的系统可能崩掉,而你还不知道问题出在哪。

       那么,有没有补救措施呢,是有的,RandomAccessFile 方法提供了另一个方法:这个方法在读到 b.length 个字节之前不会给你返回的,除非遇到文件末尾或者遇到异常。这个方法就比较靠谱了。

fa2c10a24194b6204ac8c8da62c00727.png

       而这个方法的实现是将原来的读方法套了个循环:一次没读完,我就接着读!直到读到 0 个字节,也就是读到文件末尾了。

7093dae1269b6f6598fea2c35728b34d.png

       这个方法的实现可以验证 乔老师猜想,(如果普通的 read 方法可以保证除了遇到文件末尾,都能返回需要的数据,就不需要循环读取了,只需要读一次判断 count 是否为 0 抛出异常就好了。因此,普通的 read 方法肯定还有其他原因会导致无法读取需要的数据)。

       在使用了 readFully() 方法后,我们只需要处理 EOFException(End of File Exception,读到文件末尾了还没读到要求的数据长度) 一种异常就好了。

       因此,完整的读流程为:使用 RandomAccessFile 的 readFully + 检查

897852d1127707b2f1fb536d99636f4c.png

总结

       读取文件数据时,如果使用 RandomAccessFile ,最好用 readFully(byte b[]) 方法读取数据。不管使用什么读方法,都要检查是否读取到了想要的数据,并进行异常处理。至此,java 字节流入门系列就完整了,包括读写文件,内存和磁盘交互。

       微信今天开了赞赏码,安卓和苹果都可以使用了。但是我还没有开赞赏功能!就不用之前的赞赏小程序了。如果觉得不错,可以推荐给身边的人! 

       代码:  

       https://github.com/qiaojialin/Java-IO-Learning

    更多内容推荐:

    • 了解 IoTDB 时序数据库

    • 了解更多 IoTDB 应用案例

0d1dd13f71897679be541959ec468f18.gif

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Apache IoTDB

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值