【发布时间】:2021-01-31 20:22:31
【问题描述】:
我正在构建一个通过比较哈希值来扫描文件的应用程序。我需要在超过 1GB 的散列中搜索文件的散列。我为此找到了其他解决方案,例如 Aho-Corasick,但它比 File.ReadLines(file).Contains(str) 慢。
这是迄今为止最快的代码,使用File.ReadLines。扫描一个文件大约需要 8 秒,而使用 Aho-Corasick 扫描一个文件大约需要 2 分钟。由于显而易见的原因,我无法将整个哈希文件读入内存。
IEnumerable<DirectoryInfo> directories = new DirectoryInfo(scanPath).EnumerateDirectories();
IEnumerable<FileInfo> files = new DirectoryInfo(scanPath).EnumerateFiles();
FileInfo hashes = new FileInfo(hashPath);
await Task.Run(() =>
{
IEnumerable<string> lines = File.ReadLines(hashes.FullName);
foreach (FileInfo file in files) {
if (!AuthenticodeTools.IsTrusted(file.FullName))
{
string hash = getHash(file.FullName);
if (lines.Contains(hash)) flaggedFiles.Add(file.FullName);
}
filesScanned += 1;
}
});
foreach (DirectoryInfo directory in directories)
{
await scan(directory.FullName, hashPath);
directoriesScanned += 1;
}
编辑:根据请求,以下是文件内容的示例:
5c269c9ec0255bbd9f4e20420233b1a7
63510b1eea36a23b3520e2b39c35ef4e
0955924ebc1876f0b849b3b9e45ed49d
它们是 MD5 哈希。
【问题讨论】:
-
您应该测量读取文件的时间和搜索字符串的时间。没有算法比你的硬盘更快。为此,例如,只需删除
lines.Contains代码行。 -
我会说你应该反转代码......当你编写代码时,每个文件都会重新读取 1gb 哈希文件。您可以首先枚举所有文件,计算每个名称的哈希,将这两个信息(名称+哈希)放入字典中,然后将其与哈希列表进行比较
-
或者你真的可以将哈希文件加载到内存中......如果做得好,磁盘上的 1gb 小于 500mb 的内存(因为磁盘上的哈希是十六进制格式,而在内存中你会保存它们以二进制格式)
-
如果我们进行二分搜索,我们不需要分配太多。每个散列可以二进制压缩为 16 个字节。所以我们只需要一个那么大的缓冲区
-
@TheodorZoulias 我们正处于高级原型设计阶段,甚至被称为“将 s##t 扔到墙上,看看哪个更好”:-)
标签: c# performance search large-files