2016-05-27 25 views
3

我有一个非常大的(11GB).json文件(是的,谁认为是一个好主意?),我需要抽样(读取k随机行)。Java - 从基于偏移量的随机访问文件中获取行

我不在的Java文件IO很精明,但我有,当然,发现这个职位: How to get a random line of a text file in Java?

我下探接受的答案,因为它显然方式阅读每一个太慢一行11GB文件只是为了从大约10万行中选择一个(或者更确切地说是k)。

幸运的是,贴有,我认为可能是更好的利用我的第二个建议:

使用的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(),其内放弃需要明确定位该行的右端操作。

那么为什么“寻求离开和权利到下一行终止”? 有没有更方便的方法从这两个偏移量中获取线?

回答

2

它看起来像这样做大致相同 - raf.readLine()正在寻找下一行终止符的权利;它只是为你做。


有一点要注意的是,RandomAccessFile.readLine()不支持从文件中读取Unicode字符串:

每个字节通过取字节的值的低8位转换成字符字符并将字符的高八位设置为零。因此,此方法不支持完整的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 
ⵉⵎⴰⵣⵉⵖⵏ 

因此,您可能想做自己的努力,或明确地c将raf.readLine()的结果转换为正确的字符集:

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

非常感谢。但是“如何做自己”与做'raf.readLine()''有区别,然后转换?我可以以某种方式定义一个从行首开始的InputStreamReader? – User1291

+1

从逻辑上讲,不会有任何区别;如果你自己做,它可能只涉及分配更少的对象。我将从readline/convert方法开始,如果它证明是一个性能瓶颈,那么将在稍后重新讨论。 –