用于文件哈希比较(MD5 和 SHA1)的快速程序






4.43/5 (3投票s)
一个用于计算和测量哈希比较的快速程序。
引言
通常,如果我们需要检测文件系统或文件目录中的更改,我们通常会使用 .NET 提供的文件系统观察器。 然而,在了解了它的副作用后,它似乎只是一个建议的类,并没有真正的益处。 不使用文件系统观察器类的另一个原因是,它通常不关心文件内容,而是关心整个文件系统。 因此,我发现哈希是一种更好的方法。
背景
在本文中,我将尝试回答程序员们经常问的一个关于哈希的问题,即计算目录中文件哈希需要多长时间,如果父文件夹中有子文件夹会怎样。 对于具有几兆字节文件大小的正常应用程序部署文件结构来说,速度是否足够快? 为了回答这些问题,我编写了一个小型实用工具,并在我的文件结构上运行它,该结构包含大约 45 个文件,总大小为几兆字节。 结果足够快。 计算哈希仅需 50-60 毫秒,验证哈希也需要相同的时间。
Using the Code
请查看下面的代码文件。 我尝试使用 MD5 和 SHA1 哈希算法计算哈希值。 两种算法计算文件内容的哈希值所需的时间相同。 请注意,我们在这里哈希实际的文件内容。 如果文件内容发生任何更改,即使是一个新的空格或字符,整个文件的哈希值也会更改。 然而,重要的是要注意,文件属性的任何更改,例如上次文件修改时间等,都不会影响哈希结果。
public class DeploymentFile
{
public string FilePath { get; set; }
public bool IsFilePathValid { get; set; }
public string HashedValue { get; set; }
public bool IsFileModified { get; set; }
public DeploymentFile(string filePath)
{
FilePath = filePath;
IsFilePathValid = true;
IsFileModified = false;
if (File.Exists(filePath))
HashedValue = ComputeHashSHA(filePath);
else
IsFilePathValid = false;
}
public bool IsExist(string FilePath)
{
return File.Exists(FilePath);
}
//public string ComputeHashMD5(string filename)
//{
// using (var md5 = MD5.Create())
// {
// using (var stream = File.OpenRead(filename))
// {
// return (Encoding.Default.GetString(md5.ComputeHash(stream)));
// }
// }
//}
public string ComputeHashSHA(string filename)
{
using (var sha = SHA1.Create())
{
using (var stream = File.OpenRead(filename))
{
return (Encoding.Default.GetString(sha.ComputeHash(stream)));
}
}
}
}
下面显示的是用于显示所有控件的 Form
代码。 您可能会注意到,我正在使用一个秒表来测量整个哈希计算过程所花费的时间。
重要提示:请注意,如果出现消息框,秒表会测量用户点击和关闭消息框的所有时间。 因此,为了准确测量,可以禁用消息框。
public partial class FileValidator : Form
{
public FileValidator()
{
InitializeComponent();
}
List<DeploymentFile> DeployList;
List<DeploymentFile> ValidationList;
String filePath;
#region ComputeHash
private void ComputeHash_Click(object sender, EventArgs e)
{
DeployList = new List<DeploymentFile>();
foreach (var item in GetListOfFilesInDeployFolder())
DeployList.Add(new DeploymentFile(item));
FilesGrid.DataSource = DeployList;
}
#endregion ComputeHash
#region ValidateFileHash
private void ValidateHash_Click(object sender, EventArgs e)
{
Stopwatch stopwatch = new Stopwatch();
// Begin timing.
stopwatch.Start();
bool Abort = false;
List<string> filesList = GetListOfFilesInDeployFolder();
ValidationList = new List<DeploymentFile>();
foreach (var item in DeployList)
ValidationList.Add(new DeploymentFile(item.FilePath));
//If new files are not added or deleted
for (int i = 0; i < ValidationList.Count; i++)
{
if (ValidationList.Count != filesList.Count) Abort = true;
if (ValidationList[i].FilePath != filesList[i]) Abort = true;
}
//if all files are valid and exists in directory
if (!Abort && ValidationList.Exists((x)=>x.IsFilePathValid==false))
Abort = true;
if (Abort)
{
//disable message box to calculate accurate execution time through stop watch.
MessageBox.Show("Files/Folder structure changed or modified since last check");
}
if(!Abort)
{
for (int i = 0; i < ValidationList.Count; i++)
if (ValidationList[i].HashedValue != DeployList[i].HashedValue)
{
ValidationList[i].IsFileModified = true;
Abort = true;
}
}
FilesGrid.DataSource = ValidationList;
stopwatch.Stop();
label1.Text = "Time taken in Validation : " + stopwatch.Elapsed;
}
#endregion
private List<string> GetListOfFilesInDeployFolder()
{
filePath = textBox1.Text;
return Directory.GetFiles(@filePath,"*",SearchOption.AllDirectories).ToList();
}
private void FileValidator_Load(object sender, EventArgs e)
{
FilesGrid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
}
}
上面的截图显示了计算和验证哈希值所花费的时间。 如果在点击“计算哈希”按钮和点击“检查修改”按钮之间对某些文件进行了修改,则这些修改将在 IsFilemodified
列中显示。 我还在记录文件结构并将其与文件结构进行比较,文件路径的任何更改都将在 IsFilePathValid
列中显示。
关注点
有趣的是,对于较少的文件,SHA1 和 MD5 算法花费的时间相似。 如果文件数量和文件大小增加,MD5 算法比 SHA1 更有效。 然而,SHA1 在开发人员圈子中更受信任。 我认为 MD5 更好,因为我们在这里并没有真正挑战安全性,我们更关心文件内容的完整性。