我需要随机访问文本(ASCII)文件中的特定记录,然后从那里读取,直到找到特定的“停止序列”(记录分隔符)。该文件包含多行记录,每个记录由分隔符分隔。每条记录也需要不同的行数!这是特定专业领域中众所周知的文件格式,无法更改。
我想索引文件,以便我可以快速跳转到请求的记录。
在像
这样的类似问题中How to Access string in file by position in Java
及其中的链接,answer总是引用seek()
等各种类的RandomAccessFile
方法。我知道这件事!
我遇到的问题是如何获得寻求所需的偏移量! (索引文件)
BufferedReader
没有getFilePointer()
方法或任何其他方法来从文件的开头获取当前字节偏移量。 RandomAccessFile
有一个readLine()
方法,但它的表现非常糟糕。根据我的情况,它根本不可用。
我需要逐行读取文件,每次找到记录分隔符时我都需要获取字节偏移量。我怎样才能做到这一点?
答案 0 :(得分:2)
您可以尝试将BufferedReader
类子类化以记住读取位置。但是你不会有搜索功能。
正如您所提到的,记录可以是多行的,但所有记录都由停止序列分隔。鉴于此,您可以像这样使用RandomAccessFile
:
有一个字节缓冲区byte b[]
,比方说大小为8k(这是出于性能原因)
从此缓冲区中的文件读取8k并尝试查找分隔符(如果未找到),读取另一个8k的块,但先前将数据附加到某个StringBuilder
或其他结构。
当您找到分隔符时,分隔符的位置由自上次分隔符找到后处理的字节数给出(您需要进行一些简单的数学运算)。
如果记录分隔符超过1个字符,那么棘手的部分就是如此,但这应该是个大问题。
答案 1 :(得分:2)
经过大量的谷歌搜索,试验和错误以及更多我想出了一个简单地包装RandomAccessFile
并公开所有方法的解决方案。然而,通过对readLine()
中的BufferedReader
进行微调,可以大大改善OptimizedRandomAccessFile
方法。现在表现与之相同。
这个所谓的类OptimizedRandomAccessFile raf = new OptimizedRandomAccessFile(filePath, "r");
String line = raf.readLine();
int nextByte = raf.read();
缓冲readLine()调用,只要不调用其他需要或影响文件位置的方法。例如:
nextByte
{{1}}将包含文件中下一行的第一个字节。
完整代码可在bitbucket上找到。
答案 2 :(得分:1)
我会使用以下java.io装饰器序列:
InputStreamReader <-- reader, the top reader
CountingInputStream <-- cis, stores the position (from Google Guava)
BufferedInputStream <-- speeds up file reading
FileInputStream
然后,您通过实现readLine()
方法读取此顶级阅读器,该方法逐个读取字符直到行分隔符。我不会使用BufferedReader,因为它会通过读取一个完整的固定大小的缓冲区来破坏当前位置。
因此,如果我遇到问题,算法就像
一样简单long lineStartPosition = cis.getCount();
String s = readLine(reader);
if(s.equals(DELIMITER)) { storeToIndex(lineStartPosition, recordData); }
答案 3 :(得分:0)
您可以读取所有数据文件并记录找到分隔符的位置,并将此元数据保存在其他文件中。现在,您可以使用元数据浏览文件(从一个分隔符跳转到另一个分隔符)。每次修改数据文件时,您都必须重新扫描它并重新生成元数据。