Java - 根据偏移量从随机访问文件中获取行

4

我有一个非常大的(11GB).json文件(是的,谁会认为这是个好主意?),我需要对其进行抽样(读取 k 行随机行)。

我不太熟悉Java文件IO,但我当然找到了这篇帖子:如何在Java中获取文本文件的随机行?

我放弃了被接受的答案,因为显然读取一个11GB的文件的每一行来选择其中一行(或者说 k 行)太慢了,而且行数约为10万行。

幸运的是,在那里还有第二个建议,我认为它可能更适合我:

使用RandomAccessFile在文件中寻找一个随机字节位置。

向左和向右查找下一个行终止符。让L为它们之间的行。

以(MIN_LINE_LENGTH / L.length)的概率返回L。否则,回到步骤1。

到目前为止都很好,但我想知道“让L为它们之间的行”是什么意思。

我会做这样的事情(未经测试):

RandomAccessFile raf = ...
long pos = ...
String line = getLine(raf,pos);
...

在哪里

private String getLine(RandomAccessFile raf, long start) throws IOException{
    long pos = (start % 2 == 0) ? start : start -1;
    
    if(pos == 0) return raf.readLine();
    
    do{
        pos -= 2;
        raf.seek(pos);
    }while(pos > 0 && raf.readChar() != '\n');

    pos = (pos <= 0) ? 0 : pos + 2;
    raf.seek(pos);
    return raf.readLine();
}

然后使用line.length()操作,无需显式地寻找行的右端。

那么为什么需要“向左和向右查找下一个行结束符”? 有没有更方便的方法从这两个偏移量获得行?

1个回答

2
看起来这两者大致相同- raf.readLine() 正在 寻找下一个换行符;它只是为您执行此操作。
需要注意的一点是,RandomAccessFile.readLine() 不支持从文件中读取Unicode字符串:

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

错误读取的演示:

import java.io.*;
import java.nio.charset.StandardCharsets;

class Demo {
  public static void main(String[] args) throws IOException {
    try (FileOutputStream fos = new FileOutputStream("output.txt");
         OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
         BufferedWriter writer = new BufferedWriter(osw)) {
      writer.write("ⵉⵎⴰⵣⵉⵖⵏ");
    }

    try (RandomAccessFile raf = new RandomAccessFile("output.txt", "r")) {
      System.out.println(raf.readLine());
    }
  }
}

输出:

âµâµâ´°âµ£âµâµâµ

但是output.txt确实包含了正确的数据:
$ cat output.txt
ⵉⵎⴰⵣⵉⵖⵏ

因此,您可能希望自己进行搜索,或者显式地将raf.readLine()的结果转换为正确的字符集:

String line = new String(
    raf.readLine().getBytes(StandardCharsets.ISO_8859_1),      
    StandardCharsets.UTF_8);

非常感谢。但是,“自己进行搜索”与执行“raf.readLine()”然后转换有什么区别?我是否可以定义一个从行开头开始的InputStreamReader? - User1291
1
从逻辑上讲,不会有任何区别;如果您自己操作,则可能涉及分配较少的对象。我会从readline/convert方法开始,并在以后重新审视它,如果它被证明是性能瓶颈的话。 - Andy Turner

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