生成ファイルのMD 5チェックサム

9244 ワード

Generating an MD 5 checksum of a file
Is there any simple way of generating (and checking) MD5 checksums of a list of files in Python? PythonのファイルリストのMD 5チェックサムを生成(およびチェック)する簡単な方法はありますか?(I have a small program I'm working on, and I'd like to confirm the checksums of the files). (私は小さなプログラムを処理しています.ファイルのチェックサムを確認したいです).
1階
参照先:https://stackoom.com/question/EOm1/生成されたファイルのMDチェックサム
2階
I'm clearly not adding anything fundamentally new,but added this answer before I was up to commenting status,plus the code regions make things more clear--anyway,specifically to answer@Nemo's question from Omnifarious's answer:私は明らかに新しい内容を追加していませんが、私がステータスをコメントする前にこの答えを追加しました.コード領域がより明確になりました-いずれにしても、特にOmnifariousの答えから@Nemoの質問に答えます.
I happened to be thinking about checksums a bit (came here looking for suggestions on block sizes, specifically), and have found that this method may be faster than you'd expect. 私はたまたまチェックサムを考えていて(ここではブロックサイズに関するアドバイスを探しています)、この方法はあなたが望んでいるよりも速いかもしれません.Taking the fastest(but pretty typical)timeit.timeit or /usr/bin/time result from each of several methods of checksumming a file of approx.いくつかの検査と約ファイルのファイルの方法から、最も速い(しかし典型的な)timeit.timeitまたは/usr/bin/timeの結果である.11MB: 11MB:
$ ./sum_methods.py
crc32_mmap(filename) 0.0241742134094
crc32_read(filename) 0.0219960212708
subprocess.check_output(['cksum', filename]) 0.0553209781647
md5sum_mmap(filename) 0.0286180973053
md5sum_read(filename) 0.0311000347137
subprocess.check_output(['md5sum', filename]) 0.0332629680634
$ time md5sum /tmp/test.data.300k
d3fe3d5d4c2460b5daacc30c6efbc77f  /tmp/test.data.300k

real    0m0.043s
user    0m0.032s
sys     0m0.010s
$ stat -c '%s' /tmp/test.data.300k
11890400

So, looks like both Python and/usr/bin/md5sum take about 30ms for an 11MB file. したがって、11 MBのファイルでは、Pythonおよび/usr/bin/md 5 sumは約30ミリ秒かかります.The relevant md5sum function(md5sum_read in the above listing)is pretty similar to Omnifarious's:関連するmd5sum関数(上のリストのmd5sum_read)はOmnifariousの関数と非常に似ています.
import hashlib
def md5sum(filename, blocksize=65536):
    hash = hashlib.md5()
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            hash.update(block)
    return hash.hexdigest()

Granted, these are from single runs (the mmap ones are always a smidge faster when at least a few dozen runs are made), and mine's usually got an extra f.read(blocksize) after the buffer is exhausted, but it's reasonably repeatable and shows that md5sum on the command line is not necessarily faster than a Python implementation... もちろん、これらはすべて単一の運転(少なくとも数十回の運転を行った場合、mmapは常により速くなります)であり、バッファが切れた後、私の通常は追加のf.read(blocksize)が得られますが、それはかなり繰り返し可能で、コマンドラインのmd5sumがPythonよりも速く実現されていないことを示しています.
EDIT: Sorry for the long delay, haven't looked at this in some time, but to answer @EdRandall's question, I'll write down an Adler32 implementation. 編集:申し訳ありませんが、長い遅延で、もうしばらく見ていませんが、@EdRandallの質問に答えるために、次のAdler 32実装を書きます.However, I haven't run the benchmarks for it. しかし、私はまだベンチマークテストを実行していません.It's basically the same as the CRC 32 would have been:instead of the init,update,and digest calls,everything is a zlib.adler32() call:基本的にCRC 32と同じ:初期化、更新、要約呼び出しのほか、すべての操作はzlib.adler32()呼び出しです.
import zlib
def adler32sum(filename, blocksize=65536):
    checksum = zlib.adler32("")
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            checksum = zlib.adler32(block, checksum)
    return checksum & 0xffffffff

Note that this must start off with the empty string, as Adler sums do indeed differ when starting from zero versus their sum for "" , which is 1 -- CRC can start with 0 instead. これは空の文字列から始まる必要があります.ゼロから始まると、""の合計は1であり、CRCは0から始まることができるため、Adlerの合計とは確かに異なります.The AND -ing is needed to make it a 32-bit unsigned integer, which ensures it returns the same value across Python versions. Pythonバージョン間で同じ値が返されるように、AND-ingを使用して32ビットの符号なし整数にする必要があります.
#3階
There is a way that's pretty memory inefficient . メモリの効率を低下させる方法があります.
single file:単一ファイル:
import hashlib
def file_as_bytes(file):
    with file:
        return file.read()

print hashlib.md5(file_as_bytes(open(full_path, 'rb'))).hexdigest()

list of files:ファイルリスト:
[(fname, hashlib.md5(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]

Recall though, that MD5 is known broken and should not be used for any purpose since vulnerability analysis can be really tricky, and analyzing any possible future use your code might be put to for security issues is impossible. ただし、既知のMD 5は破損しており、脆弱性分析が非常に困難であり、コードが将来セキュリティ問題に使用される可能性がある可能性があるため、目的に使用すべきではないことを覚えておいてください.IMHO, it should be flat out removed from the library so everybody who uses it is forced to update. 率直に言って、ライブラリから完全に削除して、使用するすべての人が更新する必要があります.だから、これはあなたがすべきことです.
[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]

If you only want 128 bits worth of digest you can do .digest()[:16] . 128ビットのサマリーのみが必要な場合は、.digest()[:16]を実行できます.
This will give you a list of tuples, each tuple containing the name of its file and its hash. これにより、ファイル名とハッシュ値を含むメタグループのリストが提供されます.
Again I strongly question your use of MD5. MD 5の使用を改めて強く疑問視します.You should be at least using SHA1, and given recent flaws discovered in SHA1 , probably not even that. 少なくともSHA 1を使用する必要があります.SHA 1で発見された最新の欠陥に鑑みて、ない可能性があります.Some people think that as long as you're not using MD5 for 'cryptographic' purposes, you're fine. MD 5を「暗号化」の目的で使用しない限り、それでいいと考える人もいます.But stuff has a tendency to end up being broader in scope than you initially expect, and your casual vulnerability analysis may prove completely flawed. しかし、物事の範囲は最終的にあなたが最初に予想した範囲を超える傾向があり、偶然の脆弱性分析は完全に欠陥があることを証明する可能性があります.It's best to just get in the habit of using the right algorithm out of the gate. 正しいアルゴリズムを使う習慣を身につけたほうがいい.It's just typing a different bunch of letters is all. 違うアルファベットを入力しただけです.It's not that hard. そんなに難しくないです.
Here is a way that is more complex,but memory efficient:これはより複雑でメモリが有効な方法です.
import hashlib

def hash_bytestr_iter(bytesiter, hasher, ashexstr=False):
    for block in bytesiter:
        hasher.update(block)
    return hasher.hexdigest() if ashexstr else hasher.digest()

def file_as_blockiter(afile, blocksize=65536):
    with afile:
        block = afile.read(blocksize)
        while len(block) > 0:
            yield block
            block = afile.read(blocksize)


[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.md5()))
    for fname in fnamelst]

And,again,since MD 5 is broken and should not really ever be used anymore:MD 5が壊れたので、もう使うべきではありません.
[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.sha256()))
    for fname in fnamelst]

Again, you can put [:16] after the call to hash_bytestr_iter(...) if you only want 128 bits worth of digest. 同様に、128ビットの要約のみが必要であれば、hash_bytestr_iter(...)の呼び出しの後に[:16]を配置することができる.
#4階
You can use hashlib.md 5()hashlibを使用できます.md5()
Note that sometimes you won't be able to fit the whole file in memory. ファイル全体をメモリに格納できない場合があります.In that case,you'll have to read chunks of 4096 bytes sequentially and feed them to the Md 5 function:この場合、4096バイトのブロックを順番に読み取り、Md 5関数に提供する必要があります.
def md5(fname):
    hash_md5 = hashlib.md5()
    with open(fname, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

Note: hash_md5.hexdigest() will return the hex string representation for the digest, if you just need the packed bytes use return hash_md5.digest() , so you don't have to convert back. 注:hash_md5.hexdigest()は、要約の16進数文字列表示形式を返します.パッケージされたバイトのみが必要な場合は、return hash_md5.digest()を使用します.したがって、変換する必要はありません.
#5階
hashlib.md5(pathlib.Path('path/to/file').read_bytes()).hexdigest()

#6階
I think relying on invoke package and md 5 sum binary is a bit more convenient than subprocess or md 5 package invokeパッケージとmd 5 sumバイナリファイルに頼るのはサブプロセスまたはmd 5パッケージより便利だと思います
import invoke

def get_file_hash(path):

    return invoke.Context().run("md5sum {}".format(path), hide=True).stdout.split(" ")[0]

This of course assumes you have invoke and md5sum installed. もちろん、invokeとmd 5 sumがインストールされていると仮定します.