3

我需要随机访问文本(ASCII)文件中的特定记录,然后从那里读取,直到找到特定的“停止序列”(记录分隔符)。该文件包含多行记录,每条记录由分隔符分隔。每条记录也需要不同数量的行!这是特定专业领域中众所周知的文件格式,无法更改。

我想索引文件,以便快速跳转到请求的记录。

在类似的问题中

如何在Java中按位置访问文件中的字符串

和其中的链接,答案总是引用seek()各种类的方法,如RandomAccessFile. 我知道这件事!

我遇到的问题是如何获得寻找所需的偏移量!(索引文件)

BufferedReader没有getFilePointer()方法或任何其他方法来获取从文件开头的当前字节偏移量。RandomAccessFile有一种readLine()方法,但它的性能非常糟糕。对于我的情况,它根本不可用。

我需要逐行读取文件,每次找到记录分隔符时,我都需要获取字节偏移量。我怎样才能做到这一点?

4

4 回答 4

2

您可以尝试对类进行子BufferedReader类化以记住读取位置。但是您将没有搜索功能。

正如您提到的,一条记录可以是多行的,但所有记录都由一个停止序列分隔。鉴于此,您可以RandomAccessFile像这样使用:

  1. 有一个byte b[]大小为 8k 的字节缓冲区(这是出于性能原因)

  2. 从此缓冲区中的文件中读取 8k 并尝试查找分隔符,如果未找到,则读取另一个 8k 块,但之前将数据附加到某个StringBuilder或其他结构。

  3. 当您找到分隔符时,分隔符的位置由自找到最后一个分隔符以来处理的字节数给出(您需要做一些简单的数学运算)。

棘手的部分是记录分隔符是否长于 1 个字符,但这应该是一个大问题。

于 2013-09-20T07:21:03.743 回答
2

经过大量进一步的谷歌搜索、反复试验等等,我想出了一个简单地包装RandomAccessFile和公开所有方法的解决方案。然而,通过与小调整交谈,该readLine()方法得到了很大改进。BufferedReader性能现在与它相同。

OptimizedRandomAccessFile只要没有调用其他需要或影响文件中位置的方法,这个所谓的类缓冲 readLine() 调用。例如在:

OptimizedRandomAccessFile raf = new OptimizedRandomAccessFile(filePath, "r");
String line = raf.readLine();
int nextByte = raf.read();

nextByte将包含文件中下一行的第一个字节。

完整的代码可以在bitbucket上找到。

于 2013-09-22T18:36:52.597 回答
1

我将使用以下 java.io 装饰器序列:

   InputStreamReader    <-- reader, the top reader
   CountingInputStream  <-- cis, stores the position (from Google Guava)
   BufferedInputStream  <-- speeds up file reading
   FileInputStream

readLine()然后,您通过实现一个逐行读取字符直到行分隔符的方法,从这个顶级阅读器中读取。我不会使用 BufferedReader,因为它会通过读取完整的固定大小的缓冲区来破坏当前位置。

所以如果我把问题做对了,算法就很简单

  1. long lineStartPosition = cis.getCount();
  2. String s = readLine(reader);
  3. if(s.equals(DELIMITER)) { storeToIndex(lineStartPosition, recordData); }
于 2013-09-20T21:59:31.203 回答
0

您可以读取所有数据文件并记录找到分隔符的位置,并将此元数据保存在不同的文件中。现在您可以使用元数据浏览文件(从一个分隔符跳转到另一个分隔符)。每次修改数据文件时,您都必须重新扫描它并重新生成元数据。

于 2013-09-20T07:09:35.873 回答