Comparare due file con C# tramite un algoritmo di hashing

di Roberto Albano, in .NET Framework,

In alcune situazioni può capitare la necessità di verificare due file, magari aventi nomi diversi e apparentemente non legati tra loro, per capire se rappresentano la stessa informazione.
Ovviamente la prima cosa che possiamo fare è verificare il loro peso, ovvero la grandezza in KB o MB che occupano i due file su disco, ma questo non è sufficiente per stabilire se effettivamente rappresentano la stessa informazione. Possiamo farlo invece abbastanza facilmente comparando i due file, anche nel caso di file binari, utilizzando un algoritmo di hashing.

Per chi non lo sapesse, un algoritmo di hashing (o di hash) è, detto in maniera semplice, un metodo di trasformazione irreversibile, con il quale una certa informazione viene trasformata in un'altra informazione.
L'informazione originaria, processata e trasformata attraverso un algoritmo di hashing, viene chiamata digest. Dal digest quindi non sarà più possibile risalire al dato da cui è stato generato.

Si tratta di algoritmi matematici molto complessi, che non verranno approfonditi in questa sede, almeno per il momento. Ne esistono di diversi tipi e complessità, ma le caratteristiche che più ci interessano sono:
- il processo non è reversibile (lo abbiamo appena detto);
- la lunghezza del digest è fissa (in funzione dell'algoritmo usato) indipendentemente dalla grandezza dell'informazione originaria;
- il digest è univoco, ovvero non esistono più informazioni originali diverse tra loro che producono lo stesso digest;
- il digest è legato all'informazione originale, ovvero alla stessa informazione originale corrisponde sempre lo stesso digest.

Questa velocissima introduzione su cosa sia un algoritmo di hashing lascia subito intendere che nel mondo informatico questi abbiano trovato una grossa applicabilità, per tanti motivi che non staremo qui a spiegare. Per adesso concentriamo la nostra attenzione sull'ultima caratteristica tra quelle elencate: alla stessa informazione originale corrisponde sempre lo stesso digest.
Potete capire che quindi un algoritmo di hashing può fare proprio al caso nostro. Nell'esempio creiamo un extension method per farlo, ma ovviamente non è strettamente necessario:

public static class Ext
{
  public static bool IsSameFile(this string sFile1, string sFile2)
  {
    FileStream fs1 = new FileStream(sFile1, FileMode.Open);
    FileStream fs2 = new FileStream(sFile2, FileMode.Open);

    HashAlgorithm hash = HashAlgorithm.Create("MD5");

    byte[] baHash1 = hash.ComputeHash(fs1);
    byte[] baHash2 = hash.ComputeHash(fs2);

    string sDigest1 = BitConverter.ToString(baHash1);
    string sDigest2 = BitConverter.ToString(baHash2);

    bool bFilesAreEqual = sDigest1.Equals(sDigest2);

    return bFilesAreEqual;
  }
}

Come si vede dal codice, nel nostro semplice esempio, per verificare se due file siano effettivamente identici nel contenuto, utilizziamo due FileStream, uno per ogni file, che ci serviranno ad ospitare appunto il contenuto di questi due files.

FileStream fs1 = new FileStream(sFile1, FileMode.Open);
FileStream fs2 = new FileStream(sFile2, FileMode.Open);

Una volta istanziati i due FileStream, possiamo creare una istanza della classe HashAlgoritm, che si occuperà appunto di eseguire gli hash e ottenere un digest a partire da un dato originario.

HashAlgorithm hash = HashAlgorithm.Create("MD5");

Al costruttore di questa classe basta sapere, in forma di stringa, quale algoritmo vogliamo utilizzare (tra quelli disponibili nella classe .NET).

Gli algoritmi che sono disponibili in .NET sono SHA1, MD5, SHA256, SHA384, SHA512.
La lunghezza del digest, come già spiegato prima, è fissata in funzione dell'algoritmo, e ovviamente più lungo sarà il digest da produrre, maggiore sarà il tempo necessario per produrlo.
Chiaramente con il termine "tempo" intendiamo pochi millisecondi o nel peggiore dei casi secondi, che però possono essere rilevanti in caso di operazioni batch.

Nell'esempio verrà usato l'algoritmo MD5, un algoritmo molto veloce. Con questo algoritmo, provvediamo a generare i due Digest, e quindi a confrontarli tra di loro per vedere se sono effettivamente uguali.

string sDigest1 = BitConverter.ToString(baHash1);
string sDigest2 = BitConverter.ToString(baHash2);
bool bFilesAreEqual = sDigest1.Equals(sDigest2);

In questo modo per comparare due file ci basterà scrivere:

string sFilePath1 = ...
string sFilePath2 = ...

if (sFilePath1.IsSameFile(sFilePath2))
{
  ...
}

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi