ディレクトリサイズを計算する【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