ディレクトリのサイズをまとめて計算するスクリプト
エクスプローラがディレクトリサイズの一覧を表示してくれないので、Rubyで書きました。
まずは、ひとつのディレクトリのサイズを求めるメソッドです。
def dir_size(dir_path) dir_size = 0 Dir.entries(dir_path).reject{|x|/^\.+$/=~x}.each do |file_name| file_path = File.join([dir_path, file_name]) if File.directory?(file_path) dir_size += dir_size(file_path) else dir_size += File.stat(file_path).size end end return dir_size end
処理の流れ
- 対象ディレクトリの絶対パスを引数とする。
- Dir::entries()でディレクトリ内の要素を取得。(Dir::glob()はカレントディレクトリ云々がややこしいので使用せず。)
- Enumerable#rejectで余分な要素("."と"..")を削除。
- eachで回す。
- 合計値を返す。
具体的には以下のように使用しました。
class Dir def Dir.size(dir_path) dir_size = 0 Dir.entries(dir_path).reject{|x|/^\.+$/=~x}.each do |file_name| file_path = File.join([dir_path, file_name]) if File.directory?(file_path) dir_size += size(file_path) else begin dir_size += File.stat(file_path).size rescue Errno::ENOENT puts "ファイルサイズ取得に失敗しました。ファイル名:#{file_path}" end end end return dir_size end def Dir.content_size_list(dir_path) unless File.directory?(dir_path) return [ [dir_path.split("/")[-1], File.stat(dir_path).size] ] end list = [] Dir.entries(dir_path).reject{|x|/^\.+$/=~x}.each do |file_name| file_path = File.join([dir_path, file_name]) if File.directory?(file_path) list << [file_name, size(file_path)] else begin list << [file_name, File.stat(file_path).size] rescue Errno::ENOENT puts "ファイルサイズ取得に失敗しました。ファイル名:#{file_path}" end end end return list.sort_by{|x| x[1] * -1} end end Dir.content_size_list(ARGV[0] ? ARGV[0] : "./").each do |item| puts "#{sprintf("%11d", item[1])}: #{item[0]}" end
せっかくなので、Dirクラスを拡張してみました。例外処理を入れた理由は、ファイル名に特殊な文字(はあと)が入っているファイルがあり、File::stat()した際に例外が発生して処理が止まってしまったためです。そのファイルが読めなくても大勢に影響はないので、適当にログを出して処理をスキップしています。
上のコードをそのままファイルに貼り付けて実行した場合、引数を渡せばそのディレクトリを、引数を渡さなければカレントディレクトリを検索します。ちなみに私は、
ruby (上のコードを書いたファイルの絶対パス) pause
という内容のバッチファイルを作成して使用しています。「pause」はコマンドプロンプトのコマンドです。こうすれば、調べたいディレクトリにバッチファイルを置いて実行するだけでよいので便利です。
.
.
しかし、なんでDirクラスにsize的なメソッドが組み込まれてないんだろう。ルートディレクトリで使ってPCを爆発させる人なんてそうはいないと思うけど・・・他に何か理由がある?