读取一行字符并获取文件位置

2022-05-26 00:00:00 java nio java-io

我正在从文本文件中读取连续的字符行。文件中字符的编码可能不是单字节。

在某些情况下,我想要获取下一行开始的文件位置,以便以后可以重新打开文件并快速返回到该位置。

问题

有没有一种简单的方法可以同时做到这两点,最好使用标准的Java库?

如果没有,合理的解决方法是什么?

理想解的属性

理想的解决方案是处理多个字符编码。这包括UTF-8,在UTF-8中,不同的字符可以由不同的字节数表示。理想的解决方案在很大程度上依赖于一个值得信赖、得到良好支持的库。最理想的是标准的Java库。第二好的选择是阿帕奇或谷歌的库。该解决方案必须是可扩展的。将整个文件读入内存不是解决方案。返回某个位置不应要求在线性时间内读取所有先前字符。

详细信息

对于第一个需求,BufferedReader.readLine()很有吸引力。但缓冲显然会干扰获得有意义的文件位置。

不太明显的是,InputStreamReader也可能会提前读取,从而干扰获取文件位置。来自InputStreamReader documentation:

为了能够有效地将字节转换为字符,可能会从基础流中提前读取比满足当前读取操作所需的更多的字节。

方法RandomAccessFile.readLine()reads a single byte per character。

通过获取字符低位八位的字节值并将字符的高位八位设置为零,将每个字节转换为字符。因此,此方法不支持完整的Unicode字符集。


解决方案

如果从FileReader构造BufferedReader并保持FileReader的实例可供代码访问,则应该能够通过调用:

来获取下一行的位置:
fileReader.getChannel().position();

在调用bufferedReader.readLine()之后。

如果您愿意用性能收益换取位置精度,BufferedReader可以用大小为1的输入缓冲区来构造。

替代解决方案 自己跟踪字节有什么错:

long startingPoint = 0; // or starting position if this file has been previously processed

while (readingLines) {
    String line = bufferedReader.readLine();
    startingPoint += line.getBytes().length;
}
这将为您提供精确到您已经处理过的字节数,而不考虑底层标记或缓冲。您必须在统计中考虑行尾,因为它们是去掉的。

相关文章