2016-02-22 8 views
9

大きなバイナリファイル(多くのギガバイト、メモリに読み込むことはオプションではありません)を使用して、文字列 "icpf"のすべての文字列を検索します。入力ストリームの文字列を検索する

私は、このためにstd::searchを使用してみましたが、ちょうどstd::searchは前方にのみイテレータではなく、入力イテレータのために働くという事実に噛まれてしまいました。

標準ライブラリはこれに代わるものですか?または、検索を手作業で行う必要がありますか(一度に読み取った場合はstd::search、それ以外の場合はignoreまで)、次の3文字を手動で確認してください。

答えて

1

標準ライブラリでは、これに代わる方法がありますか?

標準のC++ライブラリはテキストストリームを検索する方法を提供しますが、バイナリストリームに匹敵するアルゴリズムは提供していません。

かは、私は、検索(いずれかの後、一度にチャンクにこれらのstd::searchを読んで、またはすべてを無視し'i'まで、その後、手動で次の3つの文字を確認してください)・コードを手する必要がありますか?

エントリをスキップするソリューションを簡単にコーディングすることができるため、「スキップと検索」アプローチをコーディングするのは難しいことがあります。たとえば、"icpicpf"を含むファイル内で"icpf"を探している場合、一度に1文字を処理する単純なプログラムでは、接頭辞"icpi"を破棄した後に接尾辞"icpf"を見つけることができません。

これを自分でコーディングする場合は、Knuth–Morris–Pratt algorithmの実装を検討してください。オンラインでは多くの実装が利用可能であり、一度に1文字を考慮して戻ってこないため、ストリームで正しく動作します。

1

最も速い方法は、ファイル全体をメモリにロードしてからメモリを検索することです。

次善策は、ハードドライブを動かすことです。おそらく、データのチャンクをバッファに読み込むスレッドと、バッファを検索する別のスレッドを持つスレッドがあります。

大量のデータをバッファに読み込んだ後、バッファを検索するのは良い方法ですが、これまでの方法ほど効率的ではありません。

std::getlinestd::stringを使用して1行ずつ読むことができます。これは、入力関数が改行文字を検索している(そしてstd::stringのメモリを割り当てる)ため、ブロック読み込みと同じくらい速くはありません。

最悪の場合はおそらく文字ごとに読んでいます。関数のオーバーヘッドは、単一の文字を読み取るには悪い(通常、オーバーヘッドは大きなデータブロックを読み取る場合と同じです)。

いいえ、ファイルを検索するための標準C++ライブラリ関数はありません。一部のオペレーティングシステムにはファイルを検索するためのユーティリティがあります。おそらくあなたはそれらの1つを使うことができます。

編集1:
ボトルネックがデータを入力しています。データをバッファに取得したら、無差別な力ではなく、多くの効率的な検索アルゴリズム(最初の文字を検索してから次の文字を検索するなど)を実行します。

インターネットで「文字列検索アルゴリズム」を検索します。

0

前方に必要なイテレータを取得するために、ファイルをmmap()することが可能ですので、私は、任意の純粋な標準ライブラリソリューションを知りませんが、カーネルは、すでにプリフェッチを実装しています(エラー処理は省略)

size_t search(int fd, size_t fileSize) { 
    auto start = reinterpret_cast<char*>(
     ::mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0)); 
    ::madvise(start, fileSize, MADV_SEQUENTIAL); 
    auto pattern = "icpf"; 
    auto offset = std::search(start, start+fileSize, pattern, pattern+4); 
    return offset - start; 
} 

これは、怠惰な読み込み、プリフェッチ、および破棄を正しく行うためにカーネルを信頼して、信念を跳ね返ります。一方、これで誰かを信頼できるなら、それはおそらくカーネル開発者だろう。

免責事項:私は実際にはマルチギガバイトのファイルでこれをテストしませんでした。

関連する問題