2012-05-09 20 views
236

Używam iTextSharp do odczytu tekstu z pliku PDF. Czasami jednak nie mogę wyodrębnić tekstu, ponieważ plik PDF zawiera tylko obrazy. Codziennie pobieram te same pliki PDF i chcę sprawdzić, czy plik PDF został zmodyfikowany. Jeśli nie można uzyskać tekstu i daty modyfikacji, czy suma kontrolna jest najbardziej wiarygodnym sposobem sprawdzenia, czy plik się zmienił?Oblicz sumę kontrolną MD5 dla pliku

Jeśli tak, niektóre próbki kodu byłyby doceniane, ponieważ nie mam dużego doświadczenia z kryptografią.

+12

http://msdn.microsoft.com/en- us/library/system.security.cryptography.md5.aspx –

Odpowiedz

557

To bardzo proste przy użyciu System.Security.Cryptography.MD5: (. Uważam, że faktycznie wdrożenie MD5 używane nie należy wyrzucać, ale pewnie jeszcze zrobić tak i tak)

using (var md5 = MD5.Create()) 
{ 
    using (var stream = File.OpenRead(filename)) 
    { 
     return md5.ComputeHash(stream); 
    } 
} 

Sposób porównania wyników zależy od Ciebie; możesz na przykład przekonwertować tablicę bajtów na base64 lub porównać bajty bezpośrednio. (Należy pamiętać, że tablice nie zastępują Equals. Użycie base64 jest prostsze do uzyskania, ale nieco mniej wydajne, jeśli naprawdę interesuje Cię tylko porównanie skrótów.)

Jeśli musisz reprezentować hash jako ciąg, można przekształcić go hex za pomocą BitConverter:

static string CalculateMD5(string filename) 
{ 
    using (var md5 = MD5.Create()) 
    { 
     using (var stream = File.OpenRead(filename)) 
     { 
      var hash = md5.ComputeHash(stream); 
      return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); 
     } 
    } 
} 
+232

Jeśli chcesz "standardowego" wyglądu md5, możesz zrobić: return 'BitConverter.ToString (md5.ComputeHash (stream)). Zamień (" - "," ") .ToLower(); ' – aquinas

+0

@aquinas Jaki byłby preferowany format podczas wstawiania do bazy danych ?. – broke

+0

To byłby format, którego użyłbym. Otrzymasz taki format: 837a6f4fad381c2a7b909032133ddaf6, który prawie zawsze będzie wyglądał w formacie haszy MD5. – aquinas

2

Tu jest nieco prostsza wersja, że ​​znalazłem. Czyta cały plik za jednym razem i wymaga tylko jednej dyrektywy using.

byte[] ComputeHash(string filePath) 
{ 
    using (var md5 = MD5.Create()) 
    { 
     return md5.ComputeHash(File.ReadAllBytes(filePath)); 
    } 
} 
+38

Wadą stosowania 'ReadAllBytes' jest to, że ładuje cały plik do pojedynczej tablicy. To nie działa w ogóle dla plików większych niż 2 GiB i wywiera duży nacisk na GC nawet w przypadku plików o średnich rozmiarach Odpowiedź Jona jest tylko trochę bardziej złożona, ale nie cierpi z powodu tych problemów, więc wolę jego odpowiedź niż twoją. – CodesInChaos

+0

Wstawić 'używanie po sobie bez użycia pierwszych nawiasów klamrowych ' przy użyciu (var md5 = MD5.Create()) przy użyciu (var stream = File.OpenRead (nazwa pliku)) ' daje jeden przy użyciu p er line bez niepotrzebnego wcięcia. – NiKiZe

+0

@NiKiZe Możesz umieścić cały program na jednej linii i wyeliminować WSZYSTKIE wcięcia. Możesz nawet używać XYZ jako nazw zmiennych! Jakie są korzyści dla innych? –

49

To jak to zrobić:

using System.IO; 
using System.Security.Cryptography; 

public string checkMD5(string filename) 
{ 
    using (var md5 = MD5.Create()) 
    { 
     using (var stream = File.OpenRead(filename)) 
     { 
      return Encoding.Default.GetString(md5.ComputeHash(stream)); 
     } 
    } 
} 
+2

Poddałem się tobie, ponieważ więcej osób musi robić takie rzeczy. – Krythic

+3

Myślę, że zamiana bloków 'using' przydałaby się, ponieważ otwarcie pliku prawdopodobnie się nie powiedzie. Nieudane wczesne/szybkie podejście oszczędza zasoby potrzebne do utworzenia (i zniszczenia) instancji MD5 w takich scenariuszach. Można również pominąć nawiasy klamrowe pierwszego "używania" i zapisać poziom wcięcia bez utraty czytelności. – Palec

+8

Konwertuje wynik 16 bajtów na ciąg 16 znaków, a nie na oczekiwaną wartość 32 znaków. – NiKiZe

3

Wiem, że to pytanie zostało już odpowiedział, ale to co używam:

using (FileStream fStream = File.OpenRead(filename)) { 
    return GetHash<MD5>(fStream) 
} 

Gdzie GetHash:

public static String GetHash<T>(Stream stream) where T : HashAlgorithm { 
    StringBuilder sb = new StringBuilder(); 

    MethodInfo create = typeof(T).GetMethod("Create", new Type[] {}); 
    using (T crypt = (T) create.Invoke(null, null)) { 
     byte[] hashBytes = crypt.ComputeHash(stream); 
     foreach (byte bt in hashBytes) { 
      sb.Append(bt.ToString("x2")); 
     } 
    } 
    return sb.ToString(); 
} 

Prawdopodobnie nie jest to najlepszy sposób, ale może być przydatny.

+0

Dokonałem niewielkiej zmiany w funkcji GetHash. Przekształciłem go w metodę rozszerzenia i usunąłem kod odbicia. –

+1

'public static String GetHash (ten strumień Stream) gdzie T: HashAlgorithm, new() { StringBuilder sb = new StringBuilder(); przy użyciu (T crypt = nowy T()) { bajt [] hashBytes = crypt.ComputeHash (strumień); foreach (byte bt in hashBytes) { sb.Append (bt.ToString ("x2")); } } } return sb.ToString(); } ' –

+0

To zadziałało ... dziękuję !. Spędziłem dużo czasu szukając w Internecie wyniku, który dałby normalny 32 ciąg md5, niż bym się spodziewał. To trochę bardziej skomplikowane, ale wolałbym, ale na pewno działa. – Troublesum

Powiązane problemy