2016-04-28 308 views
6

我嘗試使用搜索一個特定的字符串一個大的文本文件(400MB)以下:如何在Java中快速搜索大文件中的字符串?

File file = new File("fileName.txt"); 
try { 
    int count = 0; 
    Scanner scanner = new Scanner(file); 
    while(scanner.hasNextLine()) { 
     if(scanner.nextLine().contains("particularString")) { 
      count++; 
      System.out.println("Number of instances of String: " + count); 
     } 
    } 
} catch (FileNotFoundException e){ 
    System.out.println(e); 
} 

這工作正常對於小文件但是,對於這個特定的文件和其他路數花費時間太長( > 10分鐘)。

這樣做最快,最有效的方法是什麼?

我現在已經更改爲以下並秒鐘內完成 -

try { 
     int count = 0; 
     FileReader fileIn = new FileReader(file); 
     BufferedReader reader = new BufferedReader(fileIn); 
     String line; 
     while((line = reader.readLine()) != null) { 
      if((line.contains("particularString"))) { 
       count++; 
       System.out.println("Number of instances of String " + count); 
      } 
     } 
    }catch (IOException e){ 
     System.out.println(e); 
    } 
+3

比較'grep -c specialString fileName的速度。txt'。 –

+0

如果他首先將整個文件讀入內存不會更快嗎? –

+1

與你的文件訪問方法無關的一件很簡單的事情是'System.out.println'調用:如果你有大量的匹配,它會*實際上減慢你的執行速度,因爲你正在構建和打印一個新的'字符串'每次。當然,這不是你在這裏尋找的真正的優化。 – Mena

回答

5

首先確定需要多長時間才能真正讀取整個文件的內容,以及需要多長時間掃描它們以查找模式。

如果你的結果被閱讀時間所支配(並且假設你正確地閱讀它,所以頻道或至少是緩衝閱讀器),那麼沒有太多的事情要做。

如果它占主導地位的掃描時間可以讀取所有行,然後將小批量行搜索到工作隊列中,您可以使用多個線程拾取行批次並在其中搜索。

球場附圖

  • 假定50 MB /秒作爲硬盤驅動器的讀取速度(並且那由現代標準慢),你應該能夠讀取整個文件到內存在< 10秒。
  • 查看MD5哈希速度基準(示例here)顯示哈希速率至少與磁盤讀取速度一樣快(通常更快)。而且,字符串搜索比散列更快,更簡單,並行性更好。

給出的2個估計,我認爲正確的實現可以很容易地降落在你的10秒量級的運行時間(如果你開始爲你讀線批次踢了尋找工作機會),並通過您的磁盤在很大程度上主導閱讀時間。

+1

好的答案,我認爲很多人會更傾向於實施批處理,並期望它超快,但實際上緩慢可能來自其他方面。 –

+0

謝謝。我已經改爲緩衝讀取器,它已經完成了這項工作,現在需要幾秒鐘。 –

-1

使用來自掃描儀對象的方法 - FindWithinHorizo​​n。掃描儀將在內部製作一個FileChannel來讀取文件。對於模式匹配,最終將使用Boyer-Moore算法進行高效的字符串搜索。

0

掃描儀在這種情況下根本無用。在底層,它可以進行各種輸入解析,檢查,緩存等等。如果你的情況只是「遍歷文件的所有行」,那麼使用基於簡單BufferedReader的東西。

在你的特殊情況下,我建議使用Files.lines。

例子:

long count = Files.lines(Paths.get("testfile.txt")) 
    .filter(s -> s.contains("particularString")) 
    .count(); 
    System.out.println(count); 

(注意,流API的這種特殊情況下可能不包括你實際上是試圖實現 - 不幸的是你的問題沒有說明方法的結果應該是什麼。 )

在我的系統上,我使用Files.lines()或緩衝讀取器獲得了大約15%的Scanner運行時間。