web-dev-qa-db-ja.com

Javaで文字列の大きなファイルをすばやく検索するにはどうすればよいですか?

次を使用して、特定の文字列を大きなテキストファイル(400MB)で検索しようとしています。

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);
    }
10
Chief DMG

最初に、ファイルの内容全体を実際に読み取るのにかかる時間と、パターンをスキャンするのにかかる時間を計算します。

結果が読み取り時間に支配されている場合(そして、適切に読み取ったと仮定すると、チャネルまたは少なくともバッファーされたリーダー)、実行することはほとんどありません。

スキャン時間が支配的である場合は、すべての行を読み取ってから、検索する行の小さなバッチを作業キューに送り、複数のスレッドで行バッチを取得してそれらを検索することができます。

野球場の数字

  • ハードドライブの読み取り速度を50 MB /秒(そして、現在の標準では遅い)とすると、ファイル全体を10秒未満でメモリに読み込むことができるはずです。
  • mD5ハッシュ速度のベンチマーク(例 here )を見ると、ハッシュレートはディスクの読み取り速度と少なくとも同じくらい(多くの場合は高速)であることがわかります。また、文字列検索はハッシュよりも高速でシンプルであり、並列化も優れています。

これらの2つの見積もりを考えると、適切な実装により、実行時間が10秒程度に簡単に到達し(行バッチを読み取るときに検索ジョブを開始する場合)、ディスクの読み取り時間が大部分を占めると思います。

8
radai

この場合、スキャナーはまったく役に立ちません。内部では、あらゆる種類の入力の解析、チェック、キャッシングなどを行います。ケースが単に「ファイルのすべての行を繰り返す」場合は、単純な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%を取得しています。

1
mtj