ディレクトリのサイズをまとめて計算するスクリプト

エクスプローラディレクトリサイズの一覧を表示してくれないので、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

処理の流れ

  1. 対象ディレクトリの絶対パスを引数とする。
  2. Dir::entries()でディレクトリ内の要素を取得。(Dir::glob()はカレントディレクトリ云々がややこしいので使用せず。)
  3. Enumerable#rejectで余分な要素("."と"..")を削除。
  4. eachで回す。
    1. File::join()でディレクトリパスとファイル名を結合。
    2. File::directory?()でディレクトリかファイルか調べる。
      1. ディレクトリなら、そのディレクトリの絶対パスを引数に自分自身を呼び出す(再帰)。
      2. ファイルなら、File::stat(path).sizeでファイルサイズを取得して合計値に加算。
  5. 合計値を返す。
※::はクラスメソッド、#はインスタンスメソッドを表します。


具体的には以下のように使用しました。

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を爆発させる人なんてそうはいないと思うけど・・・他に何か理由がある?