同一ファイルかどうかを調べるのにMD5を使うというのは、比較するファイルが両方手元にある場合はおすすめ出来ません。
重複ファイルを消すPythonスクリプト「ファイル名が違っても中身が同じファイルを探してくれる『NoClone』 | P O P * P O P」と 「404 Blog Not Found:perl - File::Find::Identical」にインスパイヤされた話ですが、 プログラム自体は数年前にPerlとmd5sumで書いて、 去年Pythonで書き直しました。 ダウンロードはこちら。
その一番の理由は、コストです。
ファイルどおしの単純比較の倍以上します。
以下は、FreeBSD 6.2、Xeon 2.66GHz x 2、400GB ATAPI 7200rpmにおいて、FreeBSD 6.2のdisc1のISOイメージを用いた速度比較の結果です。
md5コマンド
% /usr/bin/time -l /sbin/md5 6.2-RELEASE-i386-disc1.iso
MD5 (6.2-RELEASE-i386-disc1.iso) = 3d27214700687c0b5390e8b6dd3706e3
6.39 real 3.50 user 2.87 sys
576 maximum resident set size
8 average shared memory size
4 average unshared data size
128 average unshared stack size
67 page reclaims
0 page faults
0 swaps
0 block input operations
0 block output operations
0 messages sent
0 messages received
0 signals received
4 voluntary context switches
788 involuntary context switches
同等のperl one-liner
% /usr/bin/time -l perl -MDigest::MD5 -le \
'$fn=shift; open $fh, "<", $fn or die;' \
-e 'print "MD5 ($fn) = ", Digest::MD5->new->addfile($fh)->hexdigest' \
6.2-RELEASE-i386-disc1.iso
MD5 (6.2-RELEASE-i386-disc1.iso) = 3d27214700687c0b5390e8b6dd3706e3
4.66 real 3.11 user 1.52 sys
2280 maximum resident set size
8 average shared memory size
375 average unshared data size
128 average unshared stack size
241 page reclaims
0 page faults
0 swaps
0 block input operations
0 block output operations
0 messages sent
0 messages received
0 signals received
11 voluntary context switches
348 involuntary context switches
ファイルのコピー
% /usr/bin/time -l /bin/cp -p 6.2-RELEASE-i386-disc1.iso foo.iso
24.28 real 0.00 user 3.30 sys
716 maximum resident set size
12 average shared memory size
86 average unshared data size
131 average unshared stack size
80 page reclaims
0 page faults
0 swaps
0 block input operations
4587 block output operations
0 messages sent
0 messages received
0 signals received
700 voluntary context switches
895 involuntary context switches
File::Compare
% /usr/bin/time -l perl -MFile::Compare -le \
'print compare(@ARGV)+0' 6.2-RELEASE-i386-disc1.iso foo.iso
0
4.89 real 1.94 user 2.94 sys
6312 maximum resident set size
8 average shared memory size
4399 average unshared data size
128 average unshared stack size
1248 page reclaims
0 page faults
0 swaps
0 block input operations
0 block output operations
0 messages sent
0 messages received
0 signals received
1 voluntary context switches
621 involuntary context switches
md5コマンドよりもperlのone-linerの方が速いというのはちょっと意外ですが、これはおそらく用いているバッファーの大きさの違いに起因すると思われます。
それはとにかく、注目して頂きたいのは、一つのファイルのMD5 Digestを得るのに、二つのファイルを直接比較する場合と同じかそれ以上の時間がかかっているということです。
404 Blog Not Found:perl - File::Find::Identicalすでにその名もずばりのFile::Find::Duplicatesというのも存在しているのですが、速度的にも問題があるし
という理由がまさにこれでFile::Find::DuplicatesもMD5 Digestで比較しています
さらに付け加えれば、異なるデータが同一のMD5 Digestを持つことも理論的にはありえます。
ダウンロードしたファイルをチェックする場合にMD5 Digestを用いるのは、あくまでも比較するファイルの片方しか手元にないからです。ファイルの内容比較では。可能な限りFile::Compareのような、内容を単純比較する方法を用いるべきでしょう。
Dan the Man with too Many Files to Compare
また、文字列の集合を元に、その集合の要素を入力とした場合においての完全ハッシュ関数を求めるソフトウェアとして、GNU gperfがある。
任意の入力に対して衝突しないハッシュなんてありえない