たのしいRuby 復習-HDD内のサイズが大きいファイルの一覧を求める

ちょっとしたプログラムが必要なとき最近はRubyを使うことが多いわけですが、同じようなことしかしないので忘却が激しい。都度ヘルプを見てるわけですが、仕事なのでゆっくりというわけにも行かないので たのしいRuby 第2版 Rubyではじめる気軽なプログラミング を読み返す。

  • 第1章〜第14章

で、本題のプログラム

  1. Dirクラスを使って自前で再帰検索
  2. Dir.openが多重になるのを回避する

の順で作成。

一方たのしいRubyにはDir.Glob("**/*")が載っていたので試してみたが、どうもこれは一旦すべてのファイルをリストアップして配列を作るようで、ちょっと気持ちが悪い。

2009年6月2日修正

FileTest.size()を例外処理で包んでおかないと、これが例外はいたとき一気に処理が飛ばされるのを修正。なんか出力されるファイルが少ないと思って気づく orz

#! ruby -Ks

MAXNUM = 100

class InfoList
  # ファイル情報を扱うクラス
  class Info
    attr_reader :name, :size

    # ファイル名とサイズでインスタンス作成
    def initialize(name, size)
      @name = name
      @size = size
    end

    # 表示用
    def to_s
      "#{size}\t#{name}"
    end
  end

  # リストに含まれる最大ファイル数を指定
  def initialize(maxnum)
    @maxnum = maxnum
    @data = Array.new
  end

  # リストに追加
  def add(name, size)
    info = Info.new(name, size)
   index = -1
   @data.each_with_index do |d, i|  # 挿入位置を検索
     if info.size > d.size
       index = i
       break
     end
   end
   if index == -1
     @data << info  # リストが空、もしくはリスト内のものよりサイズが小さい
   else
     @data[index, 0] = info  # リストへ挿入
   end
   if @data.size > @maxnum  # 最大数を越えていれば末尾を削除
     @data.pop
   end
  end

  # リストを表示
  def show
    @data.each do |d|
      puts d
    end
    puts ""
  end
end  


# ディレクトリを検索
def traverse(top, dirs, list)
  Dir.open(top).each do |name|
    path = top + name
    next if name == "." || name == ".."
    if FileTest.directory?(path) # ディレクトリのときは保存
      dirs << path + "\\"
    else                         # ファイルはリストへ加える
      begin
        list.add(path, FileTest.size(path))
      rescue =>e
        puts e.message
      end
    end
  end
rescue =>e
  puts e.message
end


# 引数チェック
if ARGV.size == 1
  top = ARGV[0]
  maxnum = MAXNUM
elsif ARGV.size == 2
  top = ARGV[0]
  maxnum = ARGV[1].to_i
else
  puts "usage: ruby filelist.rb top_dir [max_list]"
  exit
end


# 指定ディレクトの末尾に\を加える
if top[-1] != "\\"[0]
  top += "\\"
end

list = InfoList.new(maxnum)
dirs = [top]

while dir = dirs.pop
  traverse(dir, dirs, list)
end

# 結果表示
list.show