Ich versuche, nach allen Dateien eines bestimmten Typs in einem bestimmten Ordner zu suchen und sie in einen neuen Ordner zu kopieren.
Ich muss einen Stammordner angeben und diesen Ordner und alle seine Unterordner nach Dateien durchsuchen, die dem angegebenen Typ entsprechen.
Wie durchsuche ich die Unterordner des Stammordners und ihre Unterordner? Es scheint, als würde eine rekursive Methode funktionieren, aber ich kann eine nicht richtig implementieren.
Dir.glob("#{folder}/**/*.pdf")
, wobei diefolder
Variable der Pfad zum Stammordner ist, den Sie durchsuchen möchten.Dir#[]
, was ich normalerweise benutze. Es gibt jedoch einen Haken:Dir.glob
Lädt alle Pfade in den Speicher. Dies ist normalerweise in Ordnung, aber wenn Sie eine große Anzahl von Pfaden haben, bevorzugen Sie möglicherweise stattdessen das Suchmodul, da es Pfade an den Block liefert, sobald er sie findet.Find
die Hierarchie verarbeiten zu lassen , als sie auf das Betriebssystem zu werfen und möglicherweise ein unerwartetes Array zu erhalten. Das Debuggen dieser Situation ist schwierig.Wenn Geschwindigkeit ein Problem ist, ziehen
Dir.glob
Sie es vorFind.find
.Warming up -------------------------------------- Find.find 124.000 i/100ms Dir.glob 515.000 i/100ms Calculating ------------------------------------- Find.find 1.242k (± 4.7%) i/s - 6.200k in 5.001398s Dir.glob 5.249k (± 4.5%) i/s - 26.265k in 5.014632s Comparison: Dir.glob: 5248.5 i/s Find.find: 1242.4 i/s - 4.22x slower
require 'find' require 'benchmark/ips' dir = '.' Benchmark.ips do |x| x.report 'Find.find' do Find.find(dir).select { |f| f =~ /\*\.pdf/ } end x.report 'Dir.glob' do Dir.glob("#{dir}/**/*\.pdf") end x.compare! end
Verwenden von
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin15]
quelle
Dir.glob
vs verwenden sollFind.find
.#end_with?
sie etwas genauer vergleichen ...false
und es wird immer noch deutlich langsamer (probieren Sie es aus). Dies liegt daran, dass das Aufrufen eines Blocks auch einige Zeit in Anspruch nimmt und für jedes gefundene Element erfolgt, währendglob
Filter intern und erst dann zurückgegeben werden, wenn die Ergebnisse erfasst wurden . Daher kann der verwendete Filterfind
so kompliziert sein, wie Sie möchten. Er kann aus 100 Codezeilen mit Suchvorgängen und mehreren regulären Ausdrücken bestehen, währendglob
nur ein einfaches Muster pro Aufruf verstanden wird. Wenn Sie Ihre Suche auf diese Weise ausdrücken können, bevorzugen Sieglob
.Als kleine Verbesserung der obigen Antwort von Jergason und Matt können Sie Folgendes zu einer einzigen Zeile zusammenfassen:
pdf_file_paths = Find.find('path/to/search').select { |p| /.*\.pdf$/ =~ p }
Dies verwendet die Find-Methode wie oben, nutzt jedoch die Tatsache, dass das Ergebnis eine Aufzählung ist (und als solche können wir select verwenden), um ein Array mit dem Satz von Übereinstimmungen zurückzugewinnen
quelle
Eine andere schnelle Möglichkeit besteht darin, die Aufgabe an den Shell-Befehl "find" zu delegieren und die Ausgabe aufzuteilen:
pdf_file_paths = `find #{dir} -name "*.pdf"`.split("\n")
Funktioniert nicht unter Windows.
quelle