我有一个非常大的(11GB).json文件(是的,谁认为 一个好主意?)我需要采样(阅读k
随机行)。
我在Java文件IO中不是很精明,但我当然发现了这篇文章: How to get a random line of a text file in Java?
我正在删除已接受的答案,因为显然方式太慢而无法读取11GB文件的每一行只是为了从大约100k中选择一个(或更确切地说是k
)线。
幸运的是,我认为可能对我有更好用的第二个建议:
使用RandomAccessFile寻找文件中的随机字节位置。
向左和向右寻找下一行终止符。让他们之间的界线。
以概率(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()
进行操作,这放弃了明确寻找线路右端的需要。
那么为什么“向下一行终结者寻找左和”? 有没有更方便的方法从这两个偏移中获取线路?
答案 0 :(得分: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);