从Linq Query </filehash,>返回字典<filehash,string [] =“”>

时间:2010-09-24 22:21:04

标签: c# linq file duplicates

提前感谢您的任何帮助。我甚至不确定这是否可行,但我正在尝试使用它们的哈希来获取重复文件的列表,以识别与哈希相关联的文件列表。

我有以下内容:

Dictionary<FileHash, string[]> FindDuplicateFiles(string searchFolder)
{
    Directory.GetFiles(searchFolder, "*.*")
        .Select(
            f => new
                     {
                         FileName = f,
                         FileHash = Encoding.UTF8.GetString(new SHA1Managed()
                                                                .ComputeHash(new FileStream(f,
                                                                                            FileMode.
                                                                                                OpenOrCreate,
                                                                                            FileAccess.Read)))
                     })
        .GroupBy(f => f.FileHash)
        .Select(g => new
                         {
                             FileHash = g.Key,
                             Files = g.Select(z => z.FileName).ToList()
                         })
        .GroupBy(f => f.FileHash)
        .Select(g => new {FileHash = g.Key, Files = g.Select(z => z.Files).ToArray()});

编译很好,但我只是好奇是否有办法操纵结果返回一个字典。

任何建议,备选方案和批评都将受到高度赞赏。

3 个答案:

答案 0 :(得分:0)

为IEnumerable&lt; _&gt;创建扩展方法调用toDictionary将一系列键值对转换为字典。可能会在重复键上引发异常。

为什么需要第二个GroupBy?

答案 1 :(得分:0)

您可以使用Enumerable.ToDictionary将LINQ查询收集到字典中:

var sha1 = new SHA1Managed();

Dictionary<string, string[]> result =
    Directory
        .EnumerateFiles(searchFolder)
        .GroupBy(file => Convert.ToBase64String(sha1.ComputeHash(...)))
        .ToDictionary(g => g.Key, g => g.ToArray());

一些评论:

  • 不要假设随机字节序列(例如SHA-1哈希)是有效的UTF-8字符串。
  • 考虑使用Directory.EnumerateFiles而不是Directory.GetFiles。
  • 在计算SHA-1哈希值后,不要忘记关闭FileStream。
  • Afaik可以重用SHA1Managed,因此您无需为每个文件创建一个新文件。

答案 2 :(得分:0)

已经有一种扩展方法可以做到这一点。只需将其粘贴在现有查询的末尾:

.ToDictionary(x => x.FileHash, x => x.Files);

但是:使用Encoding.UTF8.GetString任意二进制数据转换为字符串是一个非常糟糕的主意。请改用Convert.ToBase64String。哈希是不是 UTF-8编码的字符串,所以不要将其视为一个。

你也是通过哈希两次分组,我怀疑这不是你想要做的。

或者,移除之前的GroupBy来电并改为使用Lookup

var query = Directory.GetFiles(searchFolder, "*.*")
                     .Select(f => new {
                         FileName = f,
                         FileHash = Convert.ToBase64String(
                             new SHA1Managed().ComputeHash(...))
                        })
                     .ToLookup(x => x.FileHash, x => x.FileName);

这将为您提供Lookup<string, string>,基本上是按哈希分组的文件。

还有一点要注意:我怀疑你会用这种方法打开文件流。我建议你编写一个小的单独方法来根据文件的名称计算文件的哈希值,但要确保关闭流(以正常方式使用using语句)。这也将使您的查询更简单 - 类似于:

var query = Directory.GetFiles(searchFolder)
                     .ToLookup(x => ComputeHash(x));

很难进一步简化它:)