рекурсивный список файлов в Ruby - PullRequest
10 голосов
/ 02 ноября 2011

Я новичок в 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

Мои вопросы:

  1. Действительно ли File.new ОТКРЫВАЕТ файл? В Java новый File ("xxx") не ... Если мне нужно получить некоторую структуру, из которой я мог бы запросить информацию о файле (ctime, size и т. Д.) Из того, что было бы в Ruby?
  2. {| x | yield x} выглядит немного странно для меня, нормально ли это делать выходы из таких рекурсивных функций или есть какой-то способ избежать этого?
  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

(это даст вам самый старый файл из дерева)

==========

Итак, благодаря @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

Ответы [ 5 ]

11 голосов
/ 02 ноября 2011

Как насчет этого?

puts Dir['**/*.*']
5 голосов
/ 09 ноября 2011

эта штука говорит мне о том, чтобы принять ответ, я надеюсь, что он не будет против, если я отвечу сам:

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}"
5 голосов
/ 02 ноября 2011

Согласно документам File.new открывает файл.Возможно, вы захотите использовать File.stat вместо этого, которая собирает связанную с файлом статистику в запрашиваемый объект.Но обратите внимание, что статистика собирается в момент создания.Не при вызове методов запроса, таких как ctime.

Пример:

Dir['**/*'].select { |f| File.file?(f) }.map { |f| File.stat(f) }
2 голосов
/ 02 ноября 2011

Вы можете использовать встроенный Найти модуль найти метод.

1 голос
/ 28 апреля 2018

Если вы работаете в Windows, посмотрите мой ответ здесь намного быстрее (~ 26 раз), чем стандартный Ruby Dir.Если вы используете mtime, он все равно будет работать быстрее.

Если вы используете другую ОС, вы можете использовать ту же технику, мне интересно, будет ли этот выигрыш таким большим, но я почти уверен.

Как найти путь к файлу, который не является текущим файлом в ruby ​​

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...