【发布时间】:2011-11-02 16:06:28
【问题描述】:
我是 Ruby 新手(作为一名 Java 开发人员)并尝试实现一种方法(哦,对不起,一个函数),该方法将递归地检索和生成子目录中的所有文件。
我已将其实现为:
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
我的问题是:
- File.new 真的可以打开文件吗?在 Java 中 new File("xxx") 不...如果我需要产生一些结构,我可以从 Ruby 中查询文件信息(ctime、大小等)?
- { |x| yield x } 对我来说看起来有点奇怪,从这样的递归函数中进行 yield 是否可以,或者有什么方法可以避免它?
- 有什么方法可以避免检查'.'和每次迭代的“..”?
- 有没有更好的方法来实现这一点?
谢谢
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
(这将使您获得树中最旧的文件)
==========
所以,感谢@buruzaemon,我发现了很棒的 Dir.glob 函数,它为我节省了几行代码。 另外,感谢@Casper,我发现了 File.stat 方法,它使我的函数运行速度比使用 File.new 快两倍
最后我的代码看起来像这样:
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}"
=====
默认情况下,Dir.glob 会忽略以点开头的文件名(在 *nix 中被视为“隐藏”),因此添加第二个参数 File::FNM_DOTMATCH 非常重要
【问题讨论】: