Chcę uzyskać wszystkie nazwy plików z folderu za pomocą Ruby.
Chcę uzyskać wszystkie nazwy plików z folderu za pomocą Ruby.
Odpowiedzi:
Masz również opcję skrótu
Dir["/path/to/search/*"]
a jeśli chcesz znaleźć wszystkie pliki Ruby w dowolnym folderze lub podfolderze:
Dir["/path/to/search/**/*.rb"]
./...
zamiast~/
./
oznacza bieżący katalog, podczas gdy /
jest głównym punktem podłączenia i ~/
jest katalogiem domowym użytkownika. Jeśli przeniesiesz cały projekt gdzieś indziej, pierwszy zadziała, ale dwa pozostałe prawdopodobnie nie.
Dir.entries(folder)
przykład:
Dir.entries(".")
Źródło: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
na przykład może być wspomniany), nic nie stoi na przeszkodzie, aby ktoś inny opublikował naprawdę dobrą odpowiedź. „Oczywiście, jestem typem faceta„ na wpół zapełnionego ”…
Dir
rzadko i za każdym razem, gdy go potrzebuję, muszę czytać dokumentację. Wysłałem tutaj moje pytanie i odpowiedź, aby móc je później znaleźć, a może nawet pomóc komuś z tym samym pytaniem. Myślę, że słyszałem na SO podcast, że nie ma nic złego w takim zachowaniu. Jeśli masz lepszą odpowiedź, opublikuj ją. Opublikowałem to, co wiem, nie jestem rubinowym ninja. Regularnie przyjmuję odpowiedzi z największą liczbą głosów.
Dir[]
lub Dir.glob
gdy argumentem jest zmienna. Kiedy path = '/tmp'
, porównaj: Dir.glob("#{path}/*")
vs Dir.entries(path)
. Zwracane wartości są nieco inne („.”, „..”), ale te ostatnie można łatwiej sprawdzić na pierwszy rzut oka.
Poniższe fragmenty dokładnie pokazuje nazwy plików wewnątrz katalogu, pomijanie i podkatalogów "."
, ".."
przerywanymi folderach:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
dla jaśniejszego znaczenia i krótszej składni.
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
działa, ale File.file?
nie.
.reject {|f| File.directory? f}
wydaje się czystszy niż .select{|f| !File.directory? f}
. Aha, a teraz widzę pierwszy komentarz ... również dobry.
Aby rekurencyjnie uzyskać wszystkie pliki (tylko pliki):
Dir.glob('path/**/*').select{ |e| File.file? e }
Lub coś, co nie jest katalogiem ( File.file?
odrzuciłoby pliki nieregularne):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Używanie Find#find
metody wyszukiwania opartej na wzorcach jak Dir.glob
jest w rzeczywistości lepsze. Zobacz tę odpowiedź do „Jednowarstwowa lista rekurencyjnie wyświetlająca katalogi w Rubim?” .
To działa dla mnie:
Jeśli nie chcesz ukrytych plików [1], użyj 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 }
Teraz Dir.entries zwróci ukryte pliki i nie potrzebujesz wieloznacznej asterix (możesz po prostu przekazać zmienną z nazwą katalogu), ale zwróci ona bezpośrednio basename, więc funkcje File.xxx nie będą działać .
# 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
na Uniksie, nie wiem o Windowsie
W Ruby 2.5 możesz teraz używać Dir.children
. Pobiera nazwy plików jako tablicę z wyjątkiem „.” i ".."
Przykład:
Dir.children("testdir") #=> ["config.h", "main.rb"]
Osobiście uważam, że jest to najbardziej przydatne do zapętlania plików w folderze, patrząc w przyszłość:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
To jest rozwiązanie, aby znaleźć pliki w katalogu:
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
Podczas uzyskiwania wszystkich nazw plików w katalogu tego fragmentu można użyć do odrzucenia zarówno katalogów [ .
, ..
], jak i ukrytych plików, które zaczynają się od.
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
Dir.entries
zwraca lokalne nazwy plików, a nie bezwzględne ścieżki plików. Z drugiej strony File.directory?
oczekuje bezwzględnej ścieżki do pliku. Ten kod nie działa zgodnie z oczekiwaniami.
ten kod zwraca tylko nazwy plików z ich rozszerzeniem (bez ścieżki globalnej)
Dir.children("/path/to/search/")
Oto, co działa dla mnie:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
zwraca tablicę ciągów. Następnie musimy podać pełną ścieżkę do pliku File.file?
, chyba że dir
jest równa naszemu bieżącemu katalogowi roboczemu. Dlatego to File.join()
.
Możesz także użyć Rake::FileList
(pod warunkiem, że masz rake
zależność):
FileList.new('lib/*') do |file|
p file
end
Zgodnie z API:
Listy plików są leniwe. Gdy podano listę wzorców globów dla możliwych plików, które mają zostać uwzględnione na liście plików, zamiast przeszukiwać struktury plików w celu znalezienia plików, lista plików zachowuje wzorzec do późniejszego wykorzystania.
Jeśli chcesz uzyskać tablicę nazw plików, w tym dowiązania symboliczne , użyj
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
lub nawet
Dir.new('/path/to/dir').reject { |f| File.directory? f }
a jeśli chcesz przejść bez dowiązań symbolicznych , użyj
Dir.new('/path/to/dir').select { |f| File.file? f }
Jak pokazano w innych odpowiedziach, użyj Dir.glob('/path/to/dir/**/*')
zamiast, Dir.new('/path/to/dir')
jeśli chcesz uzyskać wszystkie pliki rekurencyjnie.
*.*
Oprócz sugestii w tym wątku chciałem wspomnieć, że jeśli chcesz również zwrócić pliki kropek (.gitignore itp.), W Dir.glob musisz dołączyć flagę:
Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
Domyślnie Dir.entries zawiera pliki kropek, a także bieżące katalogi nadrzędne.
Dla każdego zainteresowanego byłem ciekawy, jak tutaj odpowiedzi w porównaniu do siebie w czasie wykonania, oto wyniki przeciwko głęboko zagnieżdżonej hierarchii. Pierwsze trzy wyniki są nierekurencyjne:
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)
Zostały one wygenerowane za pomocą następującego skryptu testowego:
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
Różnice w liczbie Dir.entries
plików wynikają z domyślnego uwzględnienia plików ukrytych. Dir.entries
skończyło się to trochę dłużej w tym przypadku z powodu konieczności przebudowania bezwzględnej ścieżki do pliku, aby ustalić, czy plik jest katalogiem, ale nawet bez tego wciąż trwało to dłużej niż inne opcje w przypadku rekurencyjnym. Wszystko to przy użyciu Ruby 2.5.1 na OSX.
Jednym prostym sposobem może być:
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
zwraca ścieżki względne pliku z katalogu i wszystkich podkatalogów
W kontekście IRB możesz użyć następujących poleceń, aby pobrać pliki do bieżącego katalogu:
file_names = `ls`.split("\n")
Możesz sprawić, by działało to również w innych katalogach:
file_names = `ls ~/Documents`.split("\n")