【发布时间】:2014-07-07 20:30:00
【问题描述】:
我觉得这很奇怪。我有一个我正在使用的实用程序,它将指向一个文件夹,用相对路径/文件名/文件大小/md5哈希/其他一些东西索引文件夹。如果 md5 散列不匹配,它会更新数据库中的散列,再次备份文件,然后继续处理其余文件。这主要是出于备份目的,但也是我的倾向。
我第一次针对我的一些 Web 项目运行该程序时,它使用了磁盘 IO 和抓取文件句柄,这两者都在 Process Hacker 中可见。但是,第二次运行它(例如,我关闭它并重新启动它),它似乎没有占用任何磁盘 IO,只是定期抓取一个句柄。然而,一个哈希出现了。
遍历文件的代码:
foreach (string path in paths)
{
try
{
string relativePath = path.Replace(@"Z:\99_Projects\web\de.com\", "");
BackupFile backupFile = BackupFile.GetFile(relativePath, connection);
string md5hash = "";
long filesize = (new FileInfo(path)).Length;
using (var file = File.OpenRead(path))
{
md5hash = Hasher.ComputeMD5Hash(file);
//Console.WriteLine(md5hash);
if (backupFile == null)
{
BackupFile.NewBackupFile(relativePath, Path.GetFileName(path), md5hash, filesize, connection);
}
else
{
if (backupFile.md5 != md5hash)
backupFile.flags = CoreLib.Utils.Backup.Enums.BackupFileFlags.CHANGED;
else
backupFile.flags = CoreLib.Utils.Backup.Enums.BackupFileFlags.UNCHANGED;
backupFile.filesize = filesize;
backupFile.md5 = md5hash;
backupFile.Save(connection);
}
file.Close();
}
}
catch (IOException e)
{
Console.WriteLine("Access: " + Path.GetFileName(path));
}
catch (SQLiteException e)
{
Console.WriteLine("|E|");
}
catch (Exception e)
{
Console.WriteLine("|EG|");
throw e;
}
}
所使用的 Hasher 类的代码,它实际上只是密码学 MD5 哈希计算器的一个小方法包装器,因此我可以在其他代码的其他地方重用它(以及我粘贴在其中的其他哈希方法)。
public class Hasher
{
public static string ComputeMD5Hash(Stream stream)
{
string hash = "";
using (var md5 = System.Security.Cryptography.MD5.Create())
{
hash = BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
}
return hash;
}
}
我尝试了几件事,包括调试应用程序并验证它实际上是在打开文件流并计算哈希值。我还让它将哈希打印到控制台,如计算位置下的注释行所示,但即使它打印出来,它也根本没有显示磁盘 IO。
【问题讨论】:
-
文件很可能被缓存在内存中,因此没有实际的磁盘 I/O。至于没有得到句柄,我想它可能是得到了句柄并很快释放它,以至于你的监视器没有时间报告它。
-
确定不只是操作系统文件系统缓存在起作用?
-
@ChrisJ 是这么想的,但我不确定在哪里可以禁用它,或者至少找出它是否正在这样做。我可以在哪里调查?此外,由于文件系统缓存,它可能会如此快速地抓取它们。它确实显示了一个,但非常简短,所以这是有道理的。
-
好吧,我想测试是否是操作系统缓存的一种方法是尝试完全重新启动,并且像你一样,观察文件 I/O。
-
"我实际上更改了其中一个文件。"并且文件系统在您保存文件时缓存了该文件。并且实际的磁盘 I/O 可能发生在更晚的时间——当操作系统开始将其缓存刷新到磁盘时。