7

我有一个 4Gb 文件,我想在其上执行基于字节的查找和替换。我已经编写了一个简单的程序来执行此操作,但是仅进行一次查找和替换需要很长时间(90 分钟以上)。我尝试过的一些十六进制编辑器可以在 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

部分问题可能是您一次读取一个字节的流。尝试阅读更大的块并对其进行替换。我会从大约 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 个字节(子字符串的 len)
  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

您应该尝试使用内存映射文件。C# 从 4.0 版开始支持它们。

内存映射文件包含虚拟内存中文件的内容。

持久文件是与磁盘上的源文件相关联的内存映射文件。当最后一个进程完成对文件的处理后,数据将保存到磁盘上的源文件中。这些内存映射文件适用于处理非常大的源文件。

于 2012-04-30T17:26:34.613 回答
1

一次读取多个字节的另一种更简单的方法:

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

将此与 Saeed Amiri 的如何读入缓冲区的示例相结合,更好的二进制查找/替换算法之一应该会给您更好的结果。

于 2012-04-30T17:24:21.993 回答