【问题标题】:Processing Huge Files In C#在 C# 中处理大文件
【发布时间】:2012-05-10 09:27:25
【问题描述】:

我有一个 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“文件”相比,查找和替换相对较小。我可以很容易地看出为什么我的算法很慢,但我不确定如何才能做得更好。

【问题讨论】:

标签: c# byte large-files replace


【解决方案1】:

部分问题可能是您一次读取一个字节的流。尝试阅读更大的块并对其进行替换。我会从大约 8kb 开始,然后用一些更大或更小的块进行测试,看看什么能给你最好的性能。

【讨论】:

    【解决方案2】:

    有很多更好的算法可以在字符串中找到子字符串(这基本上就是你正在做的)

    从这里开始:

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

    它们的要点是您可以通过分析子字符串来跳过很多字节。这是一个简单的例子

    4GB 文件开头为:A B C D E F G H I J K L M N O P

    你的子字符串是:N O P

    1. 您跳过 substring-1 的长度并检查最后一个字节,因此将 C 与 P 进行比较
    2. 不匹配,所以子串不是前3个字节
    3. 此外,C 根本不在子字符串中,因此您可以再跳过 3 个字节(子字符串的 len)
    4. 比较 F 和 P,不匹配,F 不在子串中,跳过 3
    5. 将 I 与 P 等进行比较,等等

    如果匹配,请向后退。如果字符不匹配,但在子字符串中,那么您必须在此时进行更多比较(详情请阅读链接)

    【讨论】:

      【解决方案3】:

      不是逐字节读取文件,而是通过缓冲区读取文件:

      buffer = new byte[bufferSize];            
      currentPos = 0;
      length = (int)Stream .Length;
      while ((count = Stream.Read(buffer, currentPos, bufferSize)) > 0)
      {
         currentPos += count;
         ....
      }
      

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          【解决方案5】:

          您应该尝试使用memory-mapped files。 C# 从 4.0 版开始支持它们。

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-21
            • 2010-12-08
            • 2013-04-20
            • 2014-06-23
            • 2012-11-01
            • 1970-01-01
            相关资源
            最近更新 更多