在 C# 中处理大文件

本文关键字:文件 处理 | 更新日期: 2023-09-27 18:32:55

我有一个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# 中处理大文件

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

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

从这里开始:

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

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

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

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

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

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

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

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

内存

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

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