Java:从具有缓冲输入的随机访问文件中读取字符串


问题内容

之前我从未接触过Java IO API,现在真的很沮丧。我发现很难相信这是多么的奇怪和复杂,以及完成一项简单的任务有多困难。

我的任务:我有2个位置(开始字节,结束字节)pos1pos2。我需要读取这两个字节之间的行(包括开始的一个,不包括结束的一个),并将它们用作UTF8字符串对象。

例如,在大多数脚本语言中,这将是非常简单的1-2-3-liner(在Ruby中,但对于Python,Perl等基本上相同):

f = File.open("file.txt").seek(pos1)
while f.pos < pos2 {
  s = f.readline
  # do something with "s" here
}

Java IO API很快就使您陷入困境;)实际上,我看到了两种\n从常规本地文件中读取行(以结尾)的方式:

  • RandomAccessFile具有getFilePointer()seek(long pos),但它的readLine()读取非UTF8字符串(甚至不是字节数组),但是具有破损编码的非常奇怪的字符串,并且没有缓冲(这可能意味着每个read*()调用都将转换为单个不拖延的OS read()= >相当慢)。
  • BufferedReader有一个很棒的readLine()方法,它甚至可以使用进行某些搜索skip(long n),但是它无法确定已读取的偶数字节,没有提及文件中的当前位置。

我尝试使用类似:

    FileInputStream fis = new FileInputStream(fileName);
    FileChannel fc = fis.getChannel();
    BufferedReader br = new BufferedReader(
            new InputStreamReader(
                    fis,
                    CHARSET_UTF8
            )
    );

…然后fc.position()用于获取当前文件的读取位置并fc.position(newPosition)设置一个,但是在我的情况下似乎不起作用:看起来它返回由BufferedReader完成的缓冲区预填充的位置,或类似的东西-
这些计数器似乎以16K的增量取整。

我是否真的必须自己实现所有功能,即一个文件读取接口,该接口将:

  • 请允许我获取/设置文件位置
  • 缓冲文件读取操作
  • 允许读取UTF8字符串(或至少允许类似“将所有内容读取到下一个\n”之类的操作)

有没有比自己全部实施更快的方法?我在监督什么吗?


问题答案:
import org.apache.commons.io.input.BoundedInputStream

FileInputStream file = new FileInputStream(filename);
file.skip(pos1);
BufferedReader br = new BufferedReader(
   new InputStreamReader(new BoundedInputStream(file,pos2-pos1))
);

如果您不关心pos2,那么您就不需要Apache Commons IO。