Bir dosya için MD5 sağlama toplamını hesapla


334

Bir PDF dosyasındaki metni okumak için iTextSharp kullanıyorum . Ancak, PDF dosyası yalnızca görüntüler içerdiğinden, metni çıkaramadığım zamanlar var. Her gün aynı PDF dosyalarını indiriyorum ve PDF'nin değiştirilip değiştirilmediğini görmek istiyorum. Metin ve değişiklik tarihi alınamıyorsa, MD5 sağlama toplamı dosyanın değişip değişmediğini anlamanın en güvenilir yolu mudur?

Öyleyse, bazı kod örnekleri takdir edilecektir, çünkü şifreleme konusunda fazla deneyimim yok.


Yanıtlar:


773

System.Security.Cryptography.MD5'i kullanmak çok basit :

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

( Aslında kullanılan MD5 uygulamasının atılması gerekmediğine inanıyorum, ancak yine de yine de yaparım.)

Sonuçları daha sonra nasıl karşılaştıracağınız size bağlıdır; bayt dizisini örneğin base64 biçimine dönüştürebilir veya baytları doğrudan karşılaştırabilirsiniz. (Sadece dizilerin geçersiz kılmadığının farkında olun Equals. Base64 kullanmak doğru olmak için daha basit, ancak yalnızca karmaları karşılaştırmakla ilgileniyorsanız biraz daha az verimli.)

Hash'i bir dize olarak temsil etmeniz gerekiyorsa, şunu kullanarak hex'e dönüştürebilirsiniz 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();
        }
    }
}

251
"Standart" görünümlü md5 istiyorsanız, şunları yapabilirsiniz: dönüşBitConverter.ToString(md5.ComputeHash(stream)).Replace("-","").ToLower();
aquinas

78
MD5 System.Security.Cryptography'de - sadece bilgileri daha fazla ortaya çıkarmak için.
Hans

6
@KalaJ: Kasıtlı kurcalamayı tespit etmeye çalışıyorsanız, CRC32 tamamen uygunsuzdur. Yalnızca veri aktarımı hatalarını tespit etmek istiyorsanız, sorun değil. Şahsen ben muhtemelen alışkanlık dışında SHA-256 kullanacağım :) NET'te CRC32 desteği hakkında bilmiyorum, ama muhtemelen olabildiğince çabuk arayabilirsiniz :)
Jon Skeet

12
@aquinas Bence .Replace("-", String.Empty)daha iyi bir yaklaşım. Bir saatlik bir hata ayıklama oturumu geçtim, çünkü kullanıcı girdisini dosya karmasıyla karşılaştırırken yanlış sonuçlar alıyorum.
fabwu

7
@ wuethrich44, sanırım sorun aquinas yorum verbatim kodu kopyalamak / yapıştırmak olduğunu; Aynı şeyi fark ettim. Ham HTML'deki "boş" tırnak işaretleri arasında iki görünmez karakter vardır - "sıfır genişlikli birleştirici olmayan" ve Unicode "sıfır genişlikli alan" -. Orijinal yorumda olup olmadığını veya SO'nun burada suçlanacak olup olmadığını bilmiyorum.
Chris Simmons

66

Bunu nasıl yaparım:

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
Seni oyladım çünkü daha fazla insanın böyle şeyler yapması gerekiyor.
Krythic

6
Bence usingblokları değiştirmenin faydalı olacağını düşünüyorum , çünkü bir dosyayı açmak büyük olasılıkla başarısız olacaktır. Başarısız erken / hızlı yaklaşım, bu tür senaryolarda MD5 örneğini oluşturmak (ve yok etmek) için gereken kaynakları kurtarır. Ayrıca, ilk parantezleri atlayabilir ve usingokunabilirliği kaybetmeden bir girinti seviyesi kaydedebilirsiniz.
Palec

10
Bu, 16 baytlık uzun sonucu beklenen 32 karakterlik onaltılık değere değil, 16 karakterlik bir dizeye dönüştürür.
NiKiZe

3
Bu kod beklenen sonucu vermemektedir (varsayılan beklenti). @NiKiZe ile görüşme
Nick

1
@Quibblesome, sadece ifadeleri kullanma iç içe yerleştirme sırasının önemli olduğu genel fikrini teşvik etmeye çalışıyordum. Başka yerlerde, fark önemli olabilir. Neden başarısızlığı erken teşhis etme alışkanlığı uygulamıyorsunuz? Bununla birlikte, bu özel snippet'te alışkanlığın neredeyse hiç fayda getirmediğini kabul ediyorum.
Palec

7

Bu sorunun zaten cevaplandığını biliyorum, ama kullandığım şey bu:

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

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

Muhtemelen en iyi yol değil, ama kullanışlı olabilir.


GetHash işlevinizde küçük bir değişiklik yaptım. Bir uzantı yöntemine çevirdim ve yansıma kodunu kaldırdım.
Leslie Marshall

3
public static String GetHash<T>(this Stream stream) where T : HashAlgorithm, new() { StringBuilder sb = new StringBuilder(); using (T crypt = new T()) { byte[] hashBytes = crypt.ComputeHash(stream); foreach (byte bt in hashBytes) { sb.Append(bt.ToString("x2")); } } return sb.ToString(); }
Leslie Marshall

Bu gerçekten işe yaradı .... teşekkür ederim !. Beklediğimden daha normal bir 32 char md5 dize üretecek sonuç için uzun süre çevrimiçi bakarak geçirdi. Bu biraz daha karmaşık tercih ederdim ama kesinlikle işe yarıyor.
Troublesum

1
@LeslieMarshall bir uzantı yöntemi olarak kullanacaksanız, akış konumunu son konumda bırakmak yerine sıfırlamanız gerekir
MikeT

3

Bulduğum biraz daha basit bir sürüm. Tüm dosyayı tek seferde okur ve yalnızca tek bir usingyönerge gerektirir .

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

50
Kullanmanın dezavantajı ReadAllBytes, tüm dosyayı tek bir diziye yüklemesidir. Bu, 2 GiB'den büyük dosyalar için hiç işe yaramaz ve orta boyutlu dosyalar için bile GC'ye çok fazla baskı uygular. Jon'un cevabı sadece biraz daha karmaşıktır, ancak bu sorunlardan muzdarip değildir. Onun cevabını seninkine tercih ederim.
CodesInChaos

1
usingİlk kıvırcık parantez using (var md5 = MD5.Create()) using (var stream = File.OpenRead(filename))olmadan birbiri ardına s koyun, gereksiz girinti olmadan hat başına bir kullanım sağlar.
NiKiZe

3
@NiKiZe Tüm bir programı tek bir satıra koyabilir ve TÜM girintileri ortadan kaldırabilirsiniz. XYZ'yi değişken adları olarak bile kullanabilirsiniz! Başkalarına faydası nedir?
Derek Johnson

@DerekJohnson yapmaya çalıştığım nokta muhtemelen "ve sadece tek bir usingyönerge gerektirir ." her şeyi belleğe okumak için gerçekten iyi bir neden değildi. Daha etkili yaklaşım, veriye akış sağlamaktır ComputeHashve mümkünse usingsadece kullanılmalıdır, ancak ekstra girinti seviyesinden kaçınmak isteyip istemediğinizi tamamen anlayabiliyorum.
NiKiZe

3

Partiye geç kaldığımı biliyorum ama çözümü uygulamadan önce test yaptım.

Dahili MD5 sınıfı ve ayrıca md5sum.exe karşı test yaptım . Benim durumumda dahili sınıf 13 saniye sürdü nerede md5sum.exe her çalışmada çok yaklaşık 16-18 saniye.

    DateTime current = DateTime.Now;
    string file = @"C:\text.iso";//It's 2.5 Gb file
    string output;
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(file))
        {
            byte[] checksum = md5.ComputeHash(stream);
            output = BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
            Console.WriteLine("Total seconds : " + (DateTime.Now - current).TotalSeconds.ToString() + " " + output);
        }
    }

2

Ve bir Azure blobunun MD5'i ile eşleşip eşleşmediğini görmek için MD5'i hesaplamanız gerekirse, bu SO soru ve yanıtı yardımcı olabilir: Azure'a yüklenen blobun MD5 karması yerel makinede aynı dosyayla eşleşmiyor


Cevabın harika olmadığını düşünüyorsanız, aşağı oylama iyidir. Bununla birlikte, downvoate'in nedenlerini açıklayan bir yorum bırakmak, zaman içinde cevapların iyileştirilmesine yardımcı olacaktır. Bir yanıtı geliştirmek için öneriler içeren bir yorum bırakarak Yığın Taşmasına daha iyi katkıda bulunabilirsiniz. Teşekkürler!
Manfred
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.