Я хочу получить все имена файлов из папки, используя Ruby.
Я хочу получить все имена файлов из папки, используя Ruby.
Ответы:
У вас также есть опция ярлыка
Dir["/path/to/search/*"]
и если вы хотите найти все файлы Ruby в любой папке или подпапке:
Dir["/path/to/search/**/*.rb"]
./...
а не~/
./
означает текущий каталог, тогда как /
является корневой точкой монтирования и ~/
домашним каталогом пользователя. Если вы переместите весь проект куда-то еще, первый будет работать, но два других, вероятно, не будут.
Dir.entries(folder)
пример:
Dir.entries(".")
Источник: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
можно было бы упомянуть), ничто не мешает кому-то еще опубликовать действительно хороший ответ. Конечно, я в основном "наполовину полный стакан", парень ...
Dir
редко, и каждый раз, когда мне это нужно, мне приходится читать документацию. Я разместил здесь свой вопрос и ответ, чтобы найти его позже и, возможно, даже помочь кому-нибудь с тем же вопросом. Я думаю, что я слышал в SO подкасте, что нет ничего плохого в таком поведении. Если у вас есть лучший ответ, пожалуйста, напишите его. Я опубликовал то, что я знаю, я не Рубин ниндзя. Я регулярно принимаю ответы с наибольшим количеством голосов.
Dir[]
или , Dir.glob
если аргумент является переменной. Когда path = '/tmp'
, сравните: Dir.glob("#{path}/*")
против Dir.entries(path)
. Возвращаемые значения немного отличаются («.», «..»), но последние легче понять с первого взгляда.
Следующие фрагменты точно показывает имена файлов внутри каталога, пропустив подкаталоги и "."
, ".."
пунктирными папки:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
для более ясного значения и более короткого синтаксиса.
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
работает, но File.file?
нет.
.reject {|f| File.directory? f}
кажется чище чем .select{|f| !File.directory? f}
. Ох, и теперь я вижу первый комментарий ... тоже хорошо.
Чтобы получить все файлы (только файлы) рекурсивно:
Dir.glob('path/**/*').select{ |e| File.file? e }
Или все, что не является каталогом ( File.file?
будет отклонять нестандартные файлы):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Использование Find#find
более подходящего метода поиска, основанного на шаблонах, на Dir.glob
самом деле лучше. См. Этот ответ на вопрос: «Однострочное обращение к каталогам рекурсивного списка в Ruby?» ,
Это работает для меня:
Если вам не нужны скрытые файлы [1], используйте Dir [] :
# With a relative path, Dir[] will return relative paths
# as `[ './myfile', ... ]`
#
Dir[ './*' ].select{ |f| File.file? f }
# Want just the filename?
# as: [ 'myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.basename f }
# Turn them into absolute paths?
# [ '/path/to/myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.absolute_path f }
# With an absolute path, Dir[] will return absolute paths:
# as: [ '/home/../home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }
# Need the paths to be canonical?
# as: [ '/home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }.map{ |f| File.expand_path f }
Теперь Dir.entries вернет скрытые файлы, и вам не понадобится подстановочный знак звездочки (вы можете просто передать переменную с именем каталога), но он вернет базовое имя напрямую, поэтому функции File.xxx не будут работать ,
# In the current working dir:
#
Dir.entries( '.' ).select{ |f| File.file? f }
# In another directory, relative or otherwise, you need to transform the path
# so it is either absolute, or relative to the current working dir to call File.xxx functions:
#
home = "/home/test"
Dir.entries( home ).select{ |f| File.file? File.join( home, f ) }
[1] .dotfile
на Unix, я не знаю, о Windows
В Ruby 2.5 теперь можно использовать Dir.children
. Он получает имена файлов в виде массива, кроме "." а также ".."
Пример:
Dir.children("testdir") #=> ["config.h", "main.rb"]
Лично я нашел это наиболее полезным для зацикливания файлов в папке, ориентированной на будущее:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
Это решение для поиска файлов в каталоге:
files = Dir["/work/myfolder/**/*.txt"]
files.each do |file_name|
if !File.directory? file_name
puts file_name
File.open(file_name) do |file|
file.each_line do |line|
if line =~ /banco1/
puts "Found: #{line}"
end
end
end
end
end
Получая все имена файлов в каталоге, этот фрагмент можно использовать для отклонения как каталогов [ .
, ..
], так и скрытых файлов, начинающихся с.
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
Dir.entries
возвращает локальные имена файлов, а не абсолютные пути к файлам. С другой стороны, File.directory?
ожидает абсолютный путь к файлу. Этот код не работает должным образом.
этот код возвращает только имена файлов с их расширением (без глобального пути)
Dir.children("/path/to/search/")
Это то, что работает для меня:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
возвращает массив строк. Затем мы должны указать полный путь к файлу File.file?
, если он dir
не равен нашему текущему рабочему каталогу. Вот почему это File.join()
.
Вы также можете использовать Rake::FileList
(если у вас есть rake
зависимость):
FileList.new('lib/*') do |file|
p file
end
Согласно API:
Списки файлов ленивы. Когда предоставляется список шаблонов glob для возможных файлов, которые будут включены в список файлов, вместо поиска файловых структур для поиска файлов, FileList содержит шаблон для последующего использования.
Если вы хотите получить массив имен файлов, включая символические ссылки , используйте
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
или даже
Dir.new('/path/to/dir').reject { |f| File.directory? f }
и если вы хотите обойтись без символических ссылок , используйте
Dir.new('/path/to/dir').select { |f| File.file? f }
Как показано в других ответах, используйте Dir.glob('/path/to/dir/**/*')
вместо, Dir.new('/path/to/dir')
если вы хотите получить все файлы рекурсивно.
*.*
В дополнение к предложениям в этой теме я хотел бы упомянуть, что если вам нужно также возвращать точечные файлы (.gitignore и т. Д.), То в Dir.glob вам нужно будет включить флаг следующим образом:
Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
по умолчанию Dir.entries включает в себя точечные файлы, а также текущие родительские каталоги.
Для всех, кому было интересно, мне было любопытно, как ответы здесь сравниваются друг с другом во время выполнения, вот результаты против глубоко вложенной иерархии. Первые три результата не являются рекурсивными:
user system total real
Dir[*]: (34900 files stepped over 100 iterations)
0.110729 0.139060 0.249789 ( 0.249961)
Dir.glob(*): (34900 files stepped over 100 iterations)
0.112104 0.142498 0.254602 ( 0.254902)
Dir.entries(): (35600 files stepped over 100 iterations)
0.142441 0.149306 0.291747 ( 0.291998)
Dir[**/*]: (2211600 files stepped over 100 iterations)
9.399860 15.802976 25.202836 ( 25.250166)
Dir.glob(**/*): (2211600 files stepped over 100 iterations)
9.335318 15.657782 24.993100 ( 25.006243)
Dir.entries() recursive walk: (2705500 files stepped over 100 iterations)
14.653018 18.602017 33.255035 ( 33.268056)
Dir.glob(**/*, File::FNM_DOTMATCH): (2705500 files stepped over 100 iterations)
12.178823 19.577409 31.756232 ( 31.767093)
Они были сгенерированы с помощью следующего сценария тестирования:
require 'benchmark'
base_dir = "/path/to/dir/"
n = 100
Benchmark.bm do |x|
x.report("Dir[*]:") do
i = 0
n.times do
i = i + Dir["#{base_dir}*"].select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.glob(*):") do
i = 0
n.times do
i = i + Dir.glob("#{base_dir}/*").select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.entries():") do
i = 0
n.times do
i = i + Dir.entries(base_dir).select {|f| !File.directory? File.join(base_dir, f)}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir[**/*]:") do
i = 0
n.times do
i = i + Dir["#{base_dir}**/*"].select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.glob(**/*):") do
i = 0
n.times do
i = i + Dir.glob("#{base_dir}**/*").select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.entries() recursive walk:") do
i = 0
n.times do
def walk_dir(dir, result)
Dir.entries(dir).each do |file|
next if file == ".." || file == "."
path = File.join(dir, file)
if Dir.exist?(path)
walk_dir(path, result)
else
result << file
end
end
end
result = Array.new
walk_dir(base_dir, result)
i = i + result.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.glob(**/*, File::FNM_DOTMATCH):") do
i = 0
n.times do
i = i + Dir.glob("#{base_dir}**/*", File::FNM_DOTMATCH).select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
end
Различия в количестве файлов обусловлены Dir.entries
включением скрытых файлов по умолчанию. Dir.entries
в этом случае потребовалось немного больше времени из-за необходимости перестроить абсолютный путь к файлу, чтобы определить, является ли файл каталогом, но даже без этого он все еще занимал значительно больше времени, чем другие параметры в рекурсивном случае. Это все с использованием ruby 2.5.1 на OSX.
Один простой способ может быть:
dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}
files.each do |f|
puts f
end
def get_path_content(dir)
queue = Queue.new
result = []
queue << dir
until queue.empty?
current = queue.pop
Dir.entries(current).each { |file|
full_name = File.join(current, file)
if not (File.directory? full_name)
result << full_name
elsif file != '.' and file != '..'
queue << full_name
end
}
end
result
end
возвращает относительные пути файла из каталога и всех подкаталогов
В контексте IRB вы можете использовать следующее для получения файлов в текущем каталоге:
file_names = `ls`.split("\n")
Вы можете сделать эту работу и в других каталогах:
file_names = `ls ~/Documents`.split("\n")