跳转到特定行并读取其内容

3

我需要处理大文件(几个GB),并且需要快速查找以检索请求的特定行。

我的想法是维护一个映射:

some_key -> byte_location

字节位置表示文件中该行开始的位置。

编辑:问题略有改变:

首先我使用了:

FileInputStream stream = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
FileChannel channel = stream.getChannel();

我注意到FileChannel.position()不能返回读取器当前准确位置,因为它是一个“缓冲”的读取器。它按照给定大小的块(这里是16k)读取数据,所以我从FileChannel获取的是16k的倍数,并不是读取器实际读取的准确位置。
注:文件采用UTF-8编码。

你的文件采用什么编码? - Nicolas Repiquet
1
这个问题是关于什么的?如何跳转到输入流中给定的位置?in.skip(pos);。或者如何找到所需的位置以跳转并读取整行,而不是部分内容? - khachik
2个回答

3

有没有任何理由不创建一个FileInputStream,调用stream.skip(pos),然后在其周围创建一个InputStreamReader,并在InputStreamReader周围创建一个BufferedReader


InputStreamReader 是我一直在寻找的缺失环节。谢谢。 - dagnelies
@arnaud:如果你不知道想要读取的位置,那么很难解决这个问题...只读取特定行而不读取所有数据基本上是困难的。你的文件会长期保持不变吗?如果是这样,你可以花些功夫准确地读取整个文件,并记住精确的偏移量。 - Jon Skeet
计划是对所有数据进行第一次扫描,逐行读取并存储一些“检查点”:重要行及其位置。一旦这个索引在内存中,并且有请求到来,目标是跳转到最近的检查点并进行快速查找。 - dagnelies
嗯...我猜唯一的方法就是扩展这个类并自己存储位置。 - dagnelies

2
我会尝试类似这样的方法:
    RandomAccessFile raf = new RandomAccessFile(file);
    ...
    raf.seek(position);
    raf.readLine();
    ...

问题在于readLine()将每个字节转换为具有前8位为零的字符。如果您的文件是ASCII或Latin-1,则没有问题,但对于UTF-8来说会出现问题。
但是,如果您准备使用RandomAccessFile来写入文件,您可以使用readUTF()writeUTF()来读取和写入以修改后的UTF-8字符串编码的“行”。
跟进:

该死……utf-8字符被搞砸了

是的,请参见上文。
处理UTF-8的另一个方法是使用RandomAccessFile
  1. 寻找所需的位置,
  2. 使用readFully(byte[])方法将一堆字节读入到byte[]中,
  3. 在缓冲区中定位pos == 行末的位置,
  4. 如果未找到,则读取更多字节,连接并转到步骤2。
  5. 如果找到,则使用new String(bytes, 0, pos, UTF-8)将其转换为Java字符串。

这比使用readLine()更繁琐,但读取文件中多个随机顺序的行时,应该比使用FileInputStreamskip()更快。


该死...UTF-8字符出了问题。 - dagnelies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接