2016-05-27 37 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方法開始,如果它證明是一個性能瓶頸,那麼將在稍後重新討論。 –