Ich möchte mit Ruby alle Dateinamen aus einem Ordner abrufen.
Ich möchte mit Ruby alle Dateinamen aus einem Ordner abrufen.
Antworten:
Sie haben auch die Verknüpfungsoption von
Dir["/path/to/search/*"]
und wenn Sie alle Ruby-Dateien in einem Ordner oder Unterordner finden möchten:
Dir["/path/to/search/**/*.rb"]
./...
eher als~/
./
bedeutet das aktuelle Verzeichnis, während /
der Root-Mount-Punkt und ~/
das Home-Verzeichnis des Benutzers ist. Wenn Sie das gesamte Projekt an einen anderen Ort verschieben, funktioniert das erste, die beiden anderen wahrscheinlich nicht.
Dir.entries(folder)
Beispiel:
Dir.entries(".")
Quelle: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
könnte zum Beispiel vielleicht erwähnt worden sein), hindert nichts andere daran, eine wirklich gute Antwort zu veröffentlichen. Natürlich bin ich meistens ein Typ, der "halb voll" ist ...
Dir
selten und jedes Mal, wenn ich es brauche, muss ich die Dokumentation lesen. Ich habe meine Frage und Antwort hier gepostet, damit ich sie später finden und vielleicht sogar jemandem mit der gleichen Frage helfen kann. Ich glaube, ich habe bei SO Podcast gehört, dass an einem solchen Verhalten nichts auszusetzen ist. Wenn Sie eine bessere Antwort haben, posten Sie diese bitte. Ich habe gepostet, was ich weiß, ich bin kein Ruby-Ninja. Ich akzeptiere regelmäßig Antworten mit den meisten Stimmen.
Dir[]
oder Dir.glob
wenn das Argument eine Variable ist. Wenn path = '/tmp'
, zu vergleichen: Dir.glob("#{path}/*")
vs Dir.entries(path)
. Die Rückgabewerte unterscheiden sich geringfügig (".", ".."), letzteres ist jedoch auf einen Blick leichter zu erfassen.
Die folgenden Schnipsel genau zeigen den Namen der Dateien in einem Verzeichnis, das Überspringen Verzeichnisse und "."
, ".."
gepunkteter Ordner:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
für eine klarere Bedeutung und kürzere Syntax tun .
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
funktioniert aber File.file?
nicht.
.reject {|f| File.directory? f}
scheint sauberer als .select{|f| !File.directory? f}
. Oh, und jetzt sehe ich den ersten Kommentar ... auch gut.
So rekursiv alle Dateien (ausschließlich Dateien) abrufen:
Dir.glob('path/**/*').select{ |e| File.file? e }
Oder alles, was kein Verzeichnis ist ( File.file?
würde nicht reguläre Dateien ablehnen):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Die Verwendung Find#find
einer musterbasierten Suchmethode wie Dir.glob
ist eigentlich besser. Siehe diese Antwort auf "Einzeiler zum rekursiven Auflisten von Verzeichnissen in Ruby?" .
Das funktioniert bei mir:
Wenn Sie keine versteckten Dateien [1] möchten, verwenden Sie 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 }
Jetzt gibt Dir.entries versteckte Dateien zurück, und Sie benötigen keinen Platzhalter-Stern (Sie können nur die Variable mit dem Verzeichnisnamen übergeben), sondern den Basisnamen direkt zurück, sodass die Funktionen von File.xxx nicht funktionieren .
# 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] Unter .dotfile
Unix weiß ich nichts über Windows
In Ruby 2.5 können Sie jetzt verwenden Dir.children
. Es erhält Dateinamen als Array mit Ausnahme von "." und ".."
Beispiel:
Dir.children("testdir") #=> ["config.h", "main.rb"]
Persönlich fand ich dies am nützlichsten, um Dateien in einem Ordner zu durchlaufen, vorausschauende Sicherheit:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
Dies ist eine Lösung, um Dateien in einem Verzeichnis zu finden:
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
Während alle Dateinamen in einem Verzeichnis abgerufen werden, kann dieses Snippet verwendet werden, um sowohl Verzeichnisse [ .
, ..
] als auch versteckte Dateien abzulehnen , die mit a beginnen.
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
Dir.entries
Gibt lokale Dateinamen zurück, keine absoluten Dateipfade. Erwartet andererseits File.directory?
einen absoluten Dateipfad. Dieser Code funktioniert nicht wie erwartet.
Dieser Code gibt nur Dateinamen mit ihrer Erweiterung zurück (ohne globalen Pfad).
Dir.children("/path/to/search/")
Das funktioniert bei mir:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
Gibt ein Array von Zeichenfolgen zurück. Dann müssen wir einen vollständigen Pfad der Datei zu File.file?
angeben, es dir
sei denn, dies entspricht unserem aktuellen Arbeitsverzeichnis. Deshalb das File.join()
.
Möglicherweise möchten Sie auch Folgendes verwenden Rake::FileList
(vorausgesetzt, Sie haben eine rake
Abhängigkeit):
FileList.new('lib/*') do |file|
p file
end
Laut API:
Dateilisten sind faul. Wenn eine Liste von Glob-Mustern für mögliche Dateien angegeben wird, die in die Dateiliste aufgenommen werden sollen, enthält eine Dateiliste das Muster für die letztere Verwendung, anstatt die Dateistrukturen zu durchsuchen, um die Dateien zu finden.
Wenn Sie ein Array von Dateinamen einschließlich Symlinks erhalten möchten , verwenden Sie
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
oder auch
Dir.new('/path/to/dir').reject { |f| File.directory? f }
und wenn Sie ohne Symlinks auskommen möchten , verwenden Sie
Dir.new('/path/to/dir').select { |f| File.file? f }
Verwenden Sie, wie in anderen Antworten gezeigt, Dir.glob('/path/to/dir/**/*')
anstelle von, Dir.new('/path/to/dir')
wenn Sie alle Dateien rekursiv abrufen möchten.
*.*
Zusätzlich zu den Vorschlägen in diesem Thread wollte ich erwähnen, dass Sie, wenn Sie auch Punktdateien (.gitignore usw.) zurückgeben müssen, bei Dir.glob ein Flag wie folgt einfügen müssen:
Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
Standardmäßig Dir.entries Enthält Punktedateien sowie aktuelle übergeordnete Verzeichnisse.
Für alle Interessierten war ich neugierig, wie die Antworten hier im Vergleich zur Ausführungszeit miteinander verglichen wurden, hier waren die Ergebnisse gegen tief verschachtelte Hierarchien. Die ersten drei Ergebnisse sind nicht rekursiv:
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)
Diese wurden mit dem folgenden Benchmarking-Skript generiert:
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
Die Unterschiede in der Dir.entries
Anzahl der Dateien sind darauf zurückzuführen, dass standardmäßig ausgeblendete Dateien enthalten sind. Dir.entries
In diesem Fall dauerte es etwas länger, da der absolute Pfad der Datei neu erstellt werden musste, um festzustellen, ob eine Datei ein Verzeichnis war, aber auch ohne dies dauerte es im rekursiven Fall immer noch länger als die anderen Optionen. Dies alles verwendete Ruby 2.5.1 unter OSX.
Ein einfacher Weg könnte sein:
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
Gibt die relativen Pfade der Datei aus dem Verzeichnis und allen Unterverzeichnissen zurück
In einem IRB-Kontext können Sie Folgendes verwenden, um die Dateien im aktuellen Verzeichnis abzurufen:
file_names = `ls`.split("\n")
Sie können diese Funktion auch für andere Verzeichnisse verwenden:
file_names = `ls ~/Documents`.split("\n")