同一ファイルかどうかを調べるのに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