2010-09-24 6 views
0

Merci d'avance pour toute assistance. Je ne suis même pas sûr si c'est possible, mais j'essaie d'obtenir une liste de fichiers en double utilisant leurs hashes pour identifier la liste des fichiers associés aux hachages.Dictionnaire de retour <FileHash, string []> de Linq Query

J'ai ce ci-dessous:

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()}); 

Il compile très bien, mais je suis juste curieux de savoir s'il y a même un moyen de manipuler les résultats pour renvoyer un dictionnaire.

Toutes les suggestions, alternatives, critiques seraient grandement appréciées.

+0

Vous devez utiliser EnumerateFiles au lieu de GetFiles si vous avez changé à C# 4 déjà. –

+1

Ces dernières lignes sont des doublons, est-ce exprès? Mieux éditer. –

+1

Notez que vous ne pouvez pas décoder une séquence d'octets aléatoire (comme un hachage SHA-1) en une chaîne. ** Toutes les séquences d'octets ne sont pas valides UTF-8! ** – dtb

Répondre

0

Il existe déjà une méthode d'extension qui va le faire. Il suffit de coller ceci à la fin de votre requête existante:

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

Cependant: en utilisant Encoding.UTF8.GetString pour convertir en une chaîne des données binaires arbitraires est une très mauvaise idée. Utilisez Convert.ToBase64String à la place. Le hachage est et non une chaîne codée en UTF-8, donc ne le traite pas comme un.

Vous regroupez également deux fois par hachage, ce que je soupçonne n'est pas vraiment ce que vous voulez faire.

Vous pouvez également supprimer les GroupBy précédents appels et d'utiliser un Lookup à la place:

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

Cela vous donnera un Lookup<string, string>, qui est essentiellement les fichiers regroupés par hachage. Une autre chose à noter: Je suppose que vous allez laisser les flux de fichiers ouverts avec cette méthode. Je vous suggère d'écrire une petite méthode séparée pour calculer le hachage d'un fichier en fonction de son nom, mais en vous assurant de fermer le flux (avec une instruction using de la manière habituelle).Cela finira aussi par faire votre requête plus simple - quelque chose le long des lignes de:

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

Il est difficile de simplifier beaucoup plus loin :)

+0

Oui, cela semble être une bien meilleure approche. Beaucoup plus propre et plus facile pour quelqu'un qui le lit pour comprendre ce que je suis en train de faire. Je pense que j'ai aussi besoin de lire un peu sur l'algorithme de hachage à faire et à ne pas faire. Merci encore pour votre assistance. –

0

Créez une méthode d'extension à IEnumerable < _> appelée àDictionary qui convertit une séquence de paires de valeurs clés en dictionnaire. Peut déclencher une exception sur les clés en double.

Pourquoi avez-vous besoin du second GroupBy?

0

Vous pouvez utiliser Enumerable.ToDictionary pour recueillir une requête LINQ dans un dictionnaire:

var sha1 = new SHA1Managed(); 

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

Quelques remarques:

  • Ne pas supposer qu'une séquence d'octets aléatoire (comme un hachage SHA-1) est une chaîne UTF-8 valide.
  • Envisagez d'utiliser Directory.EnumerateFiles au lieu de Directory.GetFiles. N'oubliez pas de fermer le FileStream après le calcul du hachage SHA-1
  • Afaik il est possible de réutiliser un SHA1Managed, vous n'avez donc pas besoin d'en créer un nouveau pour chaque fichier.