ディレクトリサイズを計算する【glob編】

http://d.hatena.ne.jp/myokoym/20100425/1272202028の Dir.glob バージョン。

def dir_size(path)
  expath = File.expand_path(path)
  sum = 0
  Dir.glob("#{expath}/**/*") do |fn|
    # next if File.directory?(fn)
    sum += File.stat(fn).size
  end
  sum
end

かなり簡潔になりました。


ベンチマーク結果
Ruby Version:1.9.1-p378
・対象フォルダ:OpenOffice.org 3.1 のプログラムフォルダ
 ・サイズ:358MB
 ・ファイル数:3,840
 ・フォルダ数:447
・内訳
 1.前回(Dir.entries+再帰
 2.Dir.glob
 3.Dir.glob(next if File.directory?(fn)有り)

             user     system      total        real
entries:  0.484000   1.375000   1.859000 (  2.062500)
glob   :  0.188000   0.812000   1.000000 (  1.109375)
glob/n :  0.453000   1.375000   1.828000 (  1.937500)
>total:  1.125000   3.562000   4.687000 (  5.109375)
>avg:    0.375000   1.187333   1.562333 (  1.703125)

ディレクトリは0バイトで計算されるため、はじめは next で飛ばしたのですが、試しにコメントアウトしたところ2倍近く速くなりました。前回のコードも、少し工夫すれば glob を使わなくても速くなりそうです。



参考までにベンチマークテストのコードを。(リファレンスマニュアルのサンプルコードをちょっと変えただけ。ありがたや)

require 'benchmark'

n = 50000

Benchmark.benchmark(" "*7 + Benchmark::CAPTION,
                    7,
                    Benchmark::FMTSTR,
                    ">total:",
                    ">avg:") do |x|

  dir_path = "C:/Program Files/OpenOffice.org 3"

  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
    dir_size
  end

  te = x.report("entries:") {
    dir_size(dir_path)
  }
  
  def dir_size(path)
    sum = 0
    Dir.glob("#{path}/**/*") do |fn|
      sum += File.stat(fn).size
    end
    sum
  end
  
  tg = x.report("glob   :") {
    dir_size(dir_path)
  }

  def dir_size(path)
    sum = 0
    Dir.glob("#{path}/**/*") do |fn|
      next if File.directory?(fn)
      sum += File.stat(fn).size
    end
    sum
  end

  tn = x.report("glob/n :") {
    dir_size(dir_path)
  }
  
  [te+tg+tn, (te+tg+tn)/3]
end

ベンチマークの使い方は勉強が必要だー



■参考


class Dir - Ruby 1.9.1 リファレンスマニュアル
http://doc.okkez.net/static/191/class/Dir.html


library benchmark - Ruby 1.8.7 リファレンスマニュアル
http://doc.okkez.net/static/187/library/benchmark.html