Я новичок в 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 новый File ("xxx") не ... Если мне нужно получить некоторую структуру, из которой я мог бы запросить информацию о файле (ctime, size и т. Д.) Из того, что было бы в Ruby?
- {| x | yield x} выглядит немного странно для меня, нормально ли это делать выходы из таких рекурсивных функций или есть какой-то способ избежать этого?
- Есть ли способ избежать проверки на "." и '..' на каждой итерации?
- Есть ли лучший способ реализовать это?
Спасибо
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