2011-11-02 13 views
9

Ruby(Java開発者であること)に慣れていて、サブディレクトリ内のすべてのファイルを再帰的に取得して取得するメソッド(ああ、残念ですが、関数)を実装しようとしています。私の質問がありRubyの再帰的ファイルリスト

def file_list_recurse(dir) 
    Dir.foreach(dir) do |f| 
    next if f == '.' or f == '..' 
    f = dir + '/' + f 
    if File.directory? f 
     file_list_recurse(File.absolute_path f) { |x| yield x } 
    else 
     file = File.new(f) 
     yield file 
    end 
    end 
end 

::私のようにそれを実装しました

  1. File.newは本当にファイルを開きますか? Javaの新しいFile( "xxx")ではそうではありません...もし私がファイル情報(ctime、サイズなど)をRubyに照会できる構造体を生成する必要があれば?
  2. {| x | yield x}は私には少し奇妙に見えますが、これは再帰的な関数からyieldを行うことはOKですか、それとも回避する方法がありますか?
  3. 「。」のチェックを避ける方法はありますか?と '..'の繰り返しごとに?
  4. これを実装するより良い方法はありますか?

おかげ

PS: 私のメソッドの使用例は、このようなものです:

curr_file = nil 

file_list_recurse('.') do |file| 
    curr_file = file if curr_file == nil or curr_file.ctime > file.ctime 
end 

puts curr_file.to_path + ' ' + curr_file.ctime.to_s 

(それはあなたのツリーから最も古いファイルになるだろう)

= =========

@ブルーザ私はコードのいくつかの行を保存した素晴らしいDir.glob関数を見つけました。

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 
: はまた、@Casperのおかげで私は私のコードは、このような何かを探している最終的に2倍の速さFile.new

よりも私の機能の実行を作っFile.stat方法を、見つけました

それは第二引数のファイルを追加することは非常に重要ですので、デフォルトDir.globことで=====

は、(* nixの中で「隠れた」と考えられる)、ドットで始まるファイル名を無視:: FNM_DOTMATCH

答えて

5

この事は答えを受け入れて検討する私に語った、私はそれを自分自身に答える私を気にしないだろう願っています:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 
2

内蔵のを使うことができますモジュールのfindメソッド。

11

これはいかがですか?

puts Dir['**/*.*'] 
+0

素晴らしいこと!しかし、Stringオブジェクトの配列を生成します。私が探しているのは、それに基づいて私自身の計算を行うことができるようにFile-like構造を生成する関数です。最も早いctimeなどのファイルを見つける。 –

+0

ディレクトリ['。']はブロックを受け付けません。しかし、Dir.globはそうです!質問#1を除いて私の質問に答えます。 –

5

文書によれば、File.newはファイルを開きます。代わりにFile.statを使用して、ファイルに関連する統計情報をクエリ可能なオブジェクトに収集することができます。しかし、統計は作成時点で収集されていることに注意してください。 ctimeのようなクエリメソッドを呼び出すときではありません。

例:

Dir['**/*'].select { |f| File.file?(f) }.map { |f| File.stat(f) } 
+1

File.statは皮肉なことにファイルの名前を提供しないので、私のメソッドから戻るためのデータオブジェクトとして使用することはできません。 また、200,000個のファイルのツリーがあります。 あなたのサンプルを実行すると、rubyプロセスが60Mb以上になります。私のメソッド(File.newの場合でも)を実行すると、ルビは6Mbを上回ることはありません。 (私はwatch -n 0,1 "ps ax -o comm、rss | grep ruby​​ >>/tmp/q"でテストしています)。 しかし、サンプルコード行は実際にはクールに見えます;-) –