在 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"文件"相比,查找和替换相对较小。我可以很容易地理解为什么我的算法很慢,但我不确定如何才能做得更好。
部分问题可能是您一次读取一个字节的流。尝试读取较大的块并对其进行替换。我会从大约 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 的长度并检查最后一个字节,因此将 C 与 P 进行比较
- 它不匹配,因此子字符串不是前 3 个字节
- 此外,C 根本不在子字符串中,因此您可以再跳过 3 个字节(子字符串的 len(
- 将 F 与 P 进行比较,不匹配,F 不在子字符串中,跳过 3
- 将 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 开始支持它们。
内存映射文件包含虚拟内存中文件的内容。
持久化文件是与磁盘上的源文件关联的内存映射文件。当最后一个进程处理完文件后,数据将保存到磁盘上的源文件中。这些内存映射文件适用于处理非常大的源文件。