指定フォルダ内の重複ファイルを検出するプログラム

指定したフォルダ内の(サブフォルダ内も含む)全てのファイル名とサイズを取得し、同じサイズのファイル同士を比較して、内容が全く同じファイルを検出するPerlスクリプト
UTF8用なので、ソースコードもUTF8にする必要がある。Shift-JISにする場合は、"¥"を"\"に置き換える処理で2バイト文字が化ける可能性があるので、2バイト文字コードの一部を誤認しないよう処理を変える必要がある。

#! C:/Perl/bin/perl

use utf8;
use strict;
use warnings;

use File::Find::Iterator;
use File::Compare;

# File::Find::Iterator
my $find;
# filter用サブルーチン
sub isdir { -d }
sub isfile { -f }

# ファイル比較後、重複ファイルの組み合わせをリストで返す
sub binary_compare {
	my @file_list = @_;
	my @same_list = ();
	
	for (my $i = 0; $i + 1 < @file_list; $i++) {
		for (my $j = $i + 1; $j < @file_list; $j++) {
			my $diff = 0;
			# ファイル同士を比較し、同じなら組み合わせをリストに追加する
			$diff = compare($file_list[$i], $file_list[$j]);
			push (@same_list, [$file_list[$i], $file_list[$j]]) if ($diff == 0);
		}
	}
	
	return \@same_list;
}

# ベースディレクトリ(指定なしの場合カレントディレクトリ)
my $base_dir = $ARGV[0] || './';
# 区切り文字'\'を'/'に変換する
$base_dir =~ s/\\/\//gso;

# ファイル一覧取得
my @file_list;
$find = File::Find::Iterator->create(dir => [$base_dir], filter => \&isfile);
while (my $f = $find->next) { push (@file_list, $f) }

# ファイルサイズを取得し、サイズ別のハッシュにまとめる
# 仕組み : ハッシュ{ファイルサイズ} = [ファイル名1, ファイル名2, ...]
my %file_size_hash_table = ();
foreach my $file_name (@file_list) {
	my $file_size = -s $file_name;
	$file_size_hash_table{$file_size} = [] unless exists $file_size_hash_table{$file_size};
	push @{$file_size_hash_table{$file_size}}, $file_name;
}

# 同じサイズのファイル同士を全ての組み合わせで比較する
foreach my $file_size (sort keys %file_size_hash_table) {
	my $files = $file_size_hash_table{$file_size};
	
	# 同じサイズのファイルが無い場合はスキップする
	next unless (@{$files} > 1);
	
	# 複数のファイルをバイナリ比較し、重複ファイルの組み合わせを抽出する
	my $same_list = binary_compare(@{$files});
	
	# 重複ファイルがある場合、組み合わせを全て表示する
	foreach my $same_files (@{$same_list}) {
		printf ("%s == %s (%d B)\n", $same_files->[0], $same_files->[1], $file_size);
	}
}