ディレクトリ操作

Dirクラスによりディレクトリの作成、削除、ファイル一覧取得などを行うことができます。

ディレクトリを作成する

Dir::mkdirメソッドによりディレクトリを作成することができます。第2パラメタでパーミッションを設定することができます。設定されるパーミッションは指定した値とumaskのANDになります。省略時のパーミッションは0777です。

Dir::mkdir("/home/take/tmp")

Dir::mkdir("/home/take/diary", 0700)

ディレクトリを削除する

Dirクラスのrmdirメソッド、deleteメソッド、unlinkメソッドにより指定されたディレクトリを削除することができます。ただし、ディレクトリの中身は空である必要があります。

Dir::rmdir("/home/take/tmp")
Dir::delete("/home/take/diary")
Dir::unlink("/tmp/take")

中身が空でないディレクトリを削除する

Dir::rmdirメソッドなどでは削除するディレクトリの中身が空である必要がありますが、中身も含めて全て削除したいことがあります。その場合のスクリプト例を以下に示します。

# 削除するディレクトリ
DELETEDIR = "/home/take/tmp/test/"

# サブディレクトリを階層が深い順にソートした配列を作成
dirlist = Dir::glob(DELETEDIR + "**/").sort {
  |a,b| b.split('/').size <=> a.split('/').size
}

# サブディレクトリ配下の全ファイルを削除後、サブディレクトリを削除
dirlist.each {|d|
  Dir::foreach(d) {|f|
    File::delete(d+f) if ! (/\.+$/ =~ f)
  }
  Dir::rmdir(d)
}

ディレクトリを再帰的に削除する

# ファイル又はディレクトリを削除するメソッドを作成
def deleteall(delthem)
  if FileTest.directory?(delthem) then  # ディレクトリかどうかを判別
    Dir.foreach( delthem ) do |file|    # 中身を一覧
      next if /^\.+$/ =~ file           # 上位ディレクトリと自身を対象から外す
      deleteall( delthem.sub(/\/+$/,"") + "/" + file )
    end
    Dir.rmdir(delthem) rescue ""        # 中身が空になったディレクトリを削除
  else
    File.delete(delthem)                # ディレクトリでなければ削除
  end
end
# 削除
deleteall("/home/take/tmp/test/")

ディレクトリ名を変更する

File::renameメソッドによりディレクトリ名称を変更することができます。

# /home/take/sampleというディレクトリを/home/take/docに変更する

File::rename("/home/take/sample", "/home/take/doc")

ディレクトリの詳細情報を取得する

ファイルの詳細情報を取得する を参照してください。ディレクトリでもファイルと同様に処理可能です。

ディレクトリのファイルモードを変更する

ファイルモードを変更する を参照してください。ディレクトリでもファイルと同様に処理可能です。

ディレクトリの所有者とグループを変更する

ファイルの所有者とグループを変更する を参照してください。ディレクトリでもファイルと同様に処理可能です。

ディレクトリの最終アクセス時刻と最終更新日時を変更する

ファイルの最終アクセス時刻と最終更新日時を変更する を参照してください。ディレクトリでもファイルと同様に処理可能です。

カレントディレクトリの取得と変更

Dir::pwd、Dir::getwdでカレントディレクトリの取得、Dir::chdirでカレントディレクトリを変更することができます。

Dir::chdir("/tmp")
p Dir::pwd #=> "/tmp"

Dir::chdir("/home/take")
p Dir::getwd #=> "/home/take"

ディレクトリ中のファイル一覧を取得する

Dir::entriesメソッドによりディレクトリ中のファイル一覧を取得することができます。

p Dir::entries("/home/take")

ワイルドカードにマッチしたファイル全てに処理を行う

Dir::globメソッドにより指定したワイルドカードを展開し、マッチしたファイルの一覧を取得することができます。以下のようにするとマッチした全てのファイルに対して順番に処理を行うことができます。

Dir::glob("/home/take/public_html/*.html").each {|f|
  # ここにマッチしたファイルに対して行う処理を記述する
  # この例ではファイル名とファイルのサイズを標準出力へ出力している
  puts "#{f}: #{File::stat(f).size} bytes"
}

ワイルドカードに**/を指定するとサブディレクトリ配下のファイルもマッチします。以下の例では/home/take/public_html配下にある*.htmlのファイル名とファイルサイズを標準出力へ出力します。

Dir::glob("/home/take/public_html/**/*.html").each {|f|
  # ここにマッチしたファイルに対して行う処理を記述する
  # この例ではファイル名とファイルのサイズを標準出力へ出力している
  puts "#{f}: #{File::stat(f).size} bytes"
}

ワイルドカードには以下のものがあります。

*
空文字列を含む任意の文字列と一致します。
?
任意の一文字と一致します。
[ ]
[]内のいずれかの文字と一致します。A-Zのように指定すると範囲を表します。[] が ^の場合、そこに含まれない文字と一致します。
{ }
{}内で,で区切られた文字列の組合せに展開します。例えばfoo{a,b,c}はfooa, foob, foocに展開されます。他のワイルドカードと異なり、展開結果のファイルが存在している必要はありません。 ]
**/
ディレクトリを再帰的に辿りマッチを行います。例えば、foo/**/ はfoo/bar/、foo/bar/hogeなど、配下の全サブディレクトリとマッチします。

ファイル名からディレクトリ部分だけを取り出す

File::dirnameメソッドにより、/usr/local/bin/rubyなどのディレクトリ付きで指定されたファイル名からディレクトリ部分だけを切り出すことができます。

p File::dirname("/usr/local/bin/ruby") #=> "/usr/local/bin"

p File::dirname("/etc/passwd") #=> "/etc"

ディレクトリかどうか判定する

File::ftypeメソッドによりファイルの種別を判定することができます。ディレクトリかどうかを判定するには以下のようにします。

if File::ftype("/etc/") == "directory"
  puts "Directory"
else
  puts "not Directory"
end

File::ftypeメソッドはファイルの種別に応じて以下の文字列を返します。

file
通常のファイル
directory
ディレクトリ
characterSpecial
キャラクタ特殊ファイル
blockSpecial
ブロック特殊ファイル
fifo
名前付きパイプ(FIFO)
link
シンボリックリンク
socket
ソケット
unknown
不明

FileTest?#directory?関数によっても同様にディレクトリかどうかを判定することができます。

if FileTest::directory?("/etc/")
  puts "Directory"
else
  puts "not Directory"
end

ディレクトリ内の全ファイルに対して処理を行う

Dir::foreachメソッド、Dir::eachメソッドを使用するとディレクトリ配下の全ファイルに対して処理を行うことができます。以下の例はカレントディレクトリ(.)配下の全ファイルのファイル名と最終更新日時を標準出力へ出力します。

# Dir::foreachを使った例
Dir::foreach('.') {|f|
  puts "#{f}: #{File::mtime(f)}"
}

# Dir::eachを使った例
Dir::open('.') {|d|
  d.each {|f|
    puts "#{f}: #{File::mtime(f)}"
  }
}

ディレクトリ内の全ファイル名をフルパスで表示する

再帰呼び出し使用。

def recursive_dir(path)
  Dir::foreach(path) do |v|
    next if v == "." or v == ".."
    if path =~ /\/$/
      v = path + v
    else
      v = path + "/" + v
    end
    p v
    if FileTest::directory?(v)
      recursive_dir(v) #再帰呼び出し リカーシブ コール/Recursive Call
    end
  end
end

以下のように使う。再帰の練習。Dir.glob("/**/*")の方が簡単。

recursive_dir "c:/"

Dir.glob("/**/*")はルートから検索する。カレントフォルダから検索するなら Dir.glob("**/*")。

以下は、カレントフォルダ下の最後が~付きのファイルを削除する。

Dir.glob("**/*").each{|fn|
if fn=~/~$/
 p fn
 File.delete fn
end
}


Comments