7

バイトベースの検索と置換を実行したい 4Gb ファイルがあります。それを行うための簡単なプログラムを作成しましたが、検索と置換を 1 回行うだけでは時間がかかりすぎます (90 分以上)。私が試したいくつかの 16 進エディタは、3 分以内にタスクを実行でき、ターゲット ファイル全体をメモリにロードしません。同じことを達成できる方法を知っている人はいますか? これが私の現在のコードです:

    public int ReplaceBytes(string File, byte[] Find, byte[] Replace)
    {
        var Stream = new FileStream(File, FileMode.Open, FileAccess.ReadWrite);
        int FindPoint = 0;
        int Results = 0;
        for (long i = 0; i < Stream.Length; i++)
        {
            if (Find[FindPoint] == Stream.ReadByte())
            {
                FindPoint++;
                if (FindPoint > Find.Length - 1)
                {
                    Results++;
                    FindPoint = 0;
                    Stream.Seek(-Find.Length, SeekOrigin.Current);
                    Stream.Write(Replace, 0, Replace.Length);
                }
            }
            else
            {
                FindPoint = 0;
            }
        }
        Stream.Close();
        return Results;
    }

ちなみに、4Gbの「ファイル」と比較すると、検索と置換は比較的小さいです。アルゴリズムが遅い理由は簡単にわかりますが、どうしたらもっとうまくできるかわかりません。

4

5 に答える 5

3

問題の一部は、一度に1バイトずつストリームを読み取っている可能性があります。より大きなチャンクを読み取って、それらを置き換えてみてください。私は約8kbから始めて、それからいくつかのより大きなまたはより小さなチャンクでテストして、何が最高のパフォーマンスを与えるかを確認します。

于 2012-04-30T17:21:01.090 に答える
3

文字列内の部分文字列を見つけるためのより良いアルゴリズムがたくさんあります (これは基本的にあなたがしていることです)

ここから始める:

http://en.wikipedia.org/wiki/String_searching_algorithm

それらの要点は、部分文字列を分析することで多くのバイトをスキップできることです。ここに簡単な例があります

4GB ファイルは次で始まります: ABCDEFGHIJKLMNOP

あなたの部分文字列は: NOP

  1. substring-1 の長さをスキップして最後のバイトをチェックするので、C と P を比較します。
  2. 一致しないため、部分文字列は最初の 3 バイトではありません
  3. また、C は部分文字列にまったく含まれていないため、さらに 3 バイト (部分文字列の長さ) をスキップできます。
  4. F と P を比較、一致しない、F が部分文字列にない、スキップ 3
  5. I を P などと比較する

一致する場合は、後方に移動します。文字が一致しないが部分文字列にある場合は、その時点でさらに比較を行う必要があります (詳細についてはリンクを参照してください)。

于 2012-04-30T17:24:46.693 に答える
2

ファイルをバイトごとに読み取る代わりに、バッファごとに読み取ります。

buffer = new byte[bufferSize];            
currentPos = 0;
length = (int)Stream .Length;
while ((count = Stream.Read(buffer, currentPos, bufferSize)) > 0)
{
   currentPos += count;
   ....
}
于 2012-04-30T17:23:00.877 に答える
1

一度に複数のバイトを読み取る別の簡単な方法:

var Stream = new BufferedStream(new FileStream(File, FileMode.Open, FileAccess.ReadWrite));

これを Saeed Amiri のバッファーへの読み取り方法の例と組み合わせて、より優れたバイナリ検索/置換アルゴリズムの 1 つを使用すると、より良い結果が得られるはずです。

于 2012-04-30T17:24:21.993 に答える
1

メモリ マップト ファイルを使用してみてください。C# は、バージョン 4.0 以降でそれらをサポートしています。

メモリ マップト ファイルには、仮想メモリ内のファイルの内容が含まれます。

永続ファイルは、ディスク上のソース ファイルに関連付けられているメモリ マップト ファイルです。最後のプロセスがファイルの処理を終了すると、データはディスク上のソース ファイルに保存されます。これらのメモリ マップト ファイルは、非常に大きなソース ファイルの操作に適しています。

于 2012-04-30T17:26:34.613 に答える