【问题标题】:MD5 each file in a folder and also MD5 the folderMD5 文件夹中的每个文件以及 MD5 文件夹
【发布时间】:2015-06-29 14:39:56
【问题描述】:

如果我可以就我遇到的问题寻求帮助,我想打开一个文件夹来显示每个文件及其哈希值,然后在显示文件的末尾我想要一个哈希值来显示总文件夹结构。下面的代码不正确,因为它将路径 MD5 添加到文件 MD5 中。

下面的代码在列表框中显示每个文件,并在其下方显示一个哈希,但哈希代码是每个文件刚刚重复的文件夹的哈希。

private void btnFolder_Click(object sender, EventArgs e)
    {
        DialogResult result = folderBrowserDialog1.ShowDialog();
        if (result == DialogResult.OK)
        {
            _path = folderBrowserDialog1.SelectedPath;
            txtFolder.Text = _path;
            // assuming you want to include nested folders
            var files = Directory.GetFiles(_path, "*.*", SearchOption.TopDirectoryOnly)
                                 .OrderBy(p => p).ToList();
            foreach (string items in files)
            {
                MD5 md5 = MD5.Create();
                for (int i = 0; i < files.Count; i++)
                {
                    string file = files[i];
                    // hash path
                    string relativePath = file.Substring(_path.Length + 1);
                    byte[] pathBytes = Encoding.UTF8.GetBytes(relativePath.ToLower());
                    md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);

                    // hash contents
                    byte[] contentBytes = File.ReadAllBytes(file);
                    if (i == files.Count - 1)
                        md5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
                    else
                        md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
                }
                lstBox.Items.Add(items);
                lstBox.Items.Add(BitConverter.ToString(md5.Hash).Replace("-", "").ToLower());
            }
        }
        else
        {
            return;
        }
    }

提前感谢您的帮助。

【问题讨论】:

  • 你为什么要遍历你的files 数组两次? (一次是foreach,一次是for int i。这就是为什么你每次都会得到一个总哈希值,因为你每次都在哈希所有文件

标签: c# hash md5


【解决方案1】:

下面是输出您想要的输出和要求的代码。
请阅读代码中的“注意” 部分以获取更多信息。

不应该在您的 UI 线程中运行它,因为它会锁定它直到所有文件都被处理完。请查看将您的方法重构成可以在线程中调用的方法。

private void btnFolder_Click(object sender, EventArgs e)
{
  DialogResult result = folderBrowserDialog1.ShowDialog();
  if (result == DialogResult.OK)
  {
    _path = folderBrowserDialog1.SelectedPath;
    txtInput.Text = _path;
    // assuming you want to include nested folders
    var files = Directory.GetFiles(_path, "*.*", SearchOption.TopDirectoryOnly)
                          .OrderBy(p => p).ToList();

    MD5 totalMD5 = MD5.Create();
    int bytesToReadAtOnce = 2048; // NOTE: This can be changed to bigger or smaller.

    foreach (string singleFile in files)
    {
      MD5 singleMD5 = MD5.Create();

      // hash contents
      // NOTE: This is nice for small files, but a memory eater for big files
      //byte[] contentBytes = File.ReadAllBytes(singleFile);
      //singleMD5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);

      using (FileStream inputFile = File.OpenRead(singleFile))
      {
        byte[] content = new byte[bytesToReadAtOnce];
        int bytesRead = 0;
        // Read the file only in chunks, allowing minimal memory usage.
        while ((bytesRead = inputFile.Read(content, 0, bytesToReadAtOnce)) > 0)
        {
          totalMD5.TransformBlock(content, 0, bytesRead, content, 0);
          singleMD5.TransformBlock(content, 0, bytesRead, content, 0);
        }

        // Close the singleMD5 block with 0 length
        singleMD5.TransformFinalBlock(content, 0, 0);

        // Output per file
        lstBox.Items.Add(string.Format("File: {0}", singleFile));
        lstBox.Items.Add(string.Format("MD5 : {0}", BitConverter.ToString(singleMD5.Hash).Replace("-", "").ToUpper()));
      }
    }

    // Close the totalMD5 with an empty byte[] and 0 length (basically does nothing but close the Block)
    totalMD5.TransformFinalBlock(new byte[0], 0, 0);

    // Output for total
    lstBox.Items.Insert(0, Environment.NewLine);
    lstBox.Items.Insert(0, string.Format("Total MD5 : {0}", BitConverter.ToString(totalMD5.Hash).Replace("-", "").ToUpper()));
    lstBox.Items.Insert(0, string.Format("Root Path : {0}", _path));
  }
  else
  {
    return;
  }
}

由于更改为仅以块的形式读取每个文件,我不小心让这段代码在一个包含 287k 文件的文件夹上运行,总大小约为 41GB。
在整个目录处理过程中,内存使用量没有超过 7MB。

【讨论】:

  • 您的解决方案有效,但由于某种原因,MD5 散列与我拥有的 Python MD5 脚本不匹配,并且散列也不匹配 Microsoft 文件完整性验证器生成的散列... fciv.exe Python 脚本和 fciv 都在文件上给出相同的结果。
  • @Exception 您是否将每个文件的路径字符串的字节包含在 Python 和 MFIV 中生成的哈希中?如果您删除将路径字节添加到 MD5 的部分,则哈希应该匹配。
  • 对不起,伙计,我已经注释掉所有内容并更改了一个小时,但仍然无法正常工作,如果我注释掉您声明添加路径的部分我得到一个异常,指出必须在检索哈希值之前完成哈希。
  • @Exception 将路径字节添加到 MD5 是根据您的原始代码,如果这不是故意的,那么我可以修改代码以不这样做
  • 您将其设置为在列表框中显示的方式是我所追求的,即显示整个文件夹的 MD5,然后显示其中的每个文件以及每个文件 MD5,而没有文件路径 MD5添加到文件中。我将编辑原始帖子描述。我认为这是其他人想要的一个很好的解决方案。我将读取数百 GB 的文件,您的解决方案非常适合读取字节选项。
猜你喜欢
  • 2014-02-16
  • 1970-01-01
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 2020-07-11
  • 2022-06-13
  • 2018-01-03
  • 1970-01-01
相关资源
最近更新 更多