Я хочу отримати всі назви файлів із папки за допомогою 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:
Списки файлів ледачі. Коли дано список глобальних шаблонів для можливих файлів, які повинні бути включені до списку файлів, замість пошуку файлових структур для пошуку файлів, 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
у цьому випадку в цьому випадку пішло трохи більше часу через необхідність відновлення абсолютного шляху до файлу, щоб визначити, чи файл є каталогом, але навіть без цього він тривав послідовно довше, ніж інші параметри рекурсивного випадку. Для цього все використовували рубін 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")