PythonでファイルのリストのMD5チェックサムを生成(およびチェック)する簡単な方法はありますか? (私が取り組んでいる小さなプログラムがあります、そして私はファイルのチェックサムを確認したいです)。
ファイル全体をメモリに収めることができない場合があります。その場合は、4096バイトのチャンクを順番に読み込んでMd5関数に渡す必要があります。
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()
注:hash_md5.hexdigest()
はダイジェスト用の16進数文字列表現を返します。パックバイトが必要な場合はreturn hash_md5.digest()
を使用します。戻って変換する必要があります。
かなりメモリが非効率的な方法があります。
単一ファイル
import hashlib
def file_as_bytes(file):
with file:
return file.read()
print hashlib.md5(file_as_bytes(open(full_path, 'rb'))).hexdigest()
ファイルのリスト
[(fname, hashlib.md5(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
ただし、 MD5は壊れていることがわかっています 。脆弱性分析は非常に面倒であり、将来の分析にはコードを使用するため、この目的には使用できません。セキュリティ上の問題から身を守ることは不可能です。私見、それはライブラリから完全に削除されるべきであるのでそれを使う誰もが更新することを強いられます。だから、ここであなたが代わりにすべきことです:
[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
128ビット分のダイジェストだけが必要な場合は、.digest()[:16]
を実行できます。
これはあなたにタプルのリストを与えるでしょう、各タプルはそのファイルの名前とそのハッシュを含みます。
繰り返しますが、私はあなたのMD5の使用に強く疑います。少なくともSHA1を使用し、SHA1で最近発見された 最近の欠陥 をおそらく知らないでください。 MD5を「暗号」目的で使用していない限り、問題ないと考える人もいます。しかし、物事は当初想定していたよりも範囲が広くなってしまう傾向があり、あなたの偶然の脆弱性分析には完全に欠陥があるかもしれません。正しいアルゴリズムをゲートから使用する習慣を身に付けることが最善です。文字を入力するだけです。それほど難しいことではありません。
これはもっと複雑な方法ですが、メモリ効率が良いです。
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]
また、MD5は壊れているので、もう使用しないでください。
[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.sha256()))
for fname in fnamelst]
128ビット分のダイジェストだけが必要な場合は、hash_bytestr_iter(...)
の呼び出しの後に[:16]
を追加できます。
私は明らかに根本的に新しいものを追加していませんが、コメントの状態になる前にこの回答を追加しました、さらにコード領域は物事をより明確にします-とにかく、特にOmnifariousの回答から@Nemoの質問に答えるために:
私はたまたまチェックサムについて少し考えていました(具体的には、ブロックサイズに関する提案を探してここに来ました)。この方法は、予想よりも速いかもしれません。最速(ただし非常に典型的)timeit.timeit
または/usr/bin/time
を取得することは、およそのファイルをチェックサムするいくつかの方法のそれぞれの結果です。 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
したがって、Pythonと/ usr/bin/md5sumの両方が11MBのファイルで約30ミリ秒かかるようです。関連する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()
確かに、これらは単一の実行からのものです(少なくとも数十回の実行が行われると、mmap
の実行は常に高速になります)、通常は、バッファーが使い果たされた後に余分なf.read(blocksize)
を取得しますが合理的に再現可能で、コマンドラインのmd5sum
がPython実装よりも必ずしも高速ではないことを示しています...
編集:長い間遅れて申し訳ありませんが、しばらく見ていないが、@ EdRandallの質問に答えるために、Adler32実装を書き留めます。ただし、ベンチマークを実行していません。これは基本的にCRC32と同じです。init、update、digest呼び出しの代わりに、すべてが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
これは空の文字列で開始する必要があることに注意してください。Adlerの合計は、ゼロから開始する場合と""
の合計(1
-CRCは0
で始まる可能性があるため、 。 AND
- ingは、32ビットの符号なし整数にするために必要です。これにより、Pythonバージョン間で同じ値が返されます。