Je veux obtenir tous les noms de fichiers d'un dossier à l'aide de Ruby.
Je veux obtenir tous les noms de fichiers d'un dossier à l'aide de Ruby.
Réponses:
Vous avez également l'option de raccourci
Dir["/path/to/search/*"]
et si vous souhaitez trouver tous les fichiers Ruby dans n'importe quel dossier ou sous-dossier:
Dir["/path/to/search/**/*.rb"]
./...
plutôt que~/
./
signifie le répertoire courant, alors que /
c'est le point de montage racine, et ~/
est le répertoire personnel de l'utilisateur. Si vous déplacez l'ensemble du projet ailleurs, le premier fonctionnera, mais les deux autres ne le seront probablement pas.
Dir.entries(folder)
exemple:
Dir.entries(".")
Source: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
aurait peut-être pu être mentionné, par exemple), rien n'empêche quelqu'un d'autre de poster une très bonne réponse. Bien sûr, je suis surtout une sorte de "verre à moitié plein" ...
Dir
rarement, et chaque fois que j'en ai besoin, je dois lire la documentation. J'ai posté ma question et ma réponse ici pour que je puisse la retrouver plus tard, et peut-être même aider quelqu'un avec la même question. Je pense avoir entendu au podcast SO qu'il n'y a rien de mal à un tel comportement. Si vous avez une meilleure réponse, veuillez la poster. J'ai posté ce que je sais, je ne suis pas un ninja Ruby. J'accepte régulièrement les réponses avec le plus de votes.
Dir[]
ou Dir.glob
lorsque l'argument est une variable. Lorsque path = '/tmp'
, comparez: Dir.glob("#{path}/*")
vs Dir.entries(path)
. Les valeurs de retour sont légèrement différentes (".", ".."), mais ce dernier est plus facile à cerner d'un coup d'œil.
Les extraits suivants montrent exactement le nom des fichiers dans un répertoire, et sauter les sous - répertoires "."
, ".."
dossiers en pointillés:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
pour une signification plus claire et une syntaxe plus courte.
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
fonctionne mais File.file?
pas.
.reject {|f| File.directory? f}
semble plus propre que .select{|f| !File.directory? f}
. Oh, et maintenant je vois le premier commentaire ... aussi bien.
Pour obtenir tous les fichiers (strictement les fichiers uniquement) de manière récursive:
Dir.glob('path/**/*').select{ |e| File.file? e }
Ou tout ce qui n'est pas un répertoire ( File.file?
rejetterait les fichiers non réguliers):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Il est préférable d' utiliser Find#find
une méthode de recherche basée sur un modèle comme Dir.glob
. Voir cette réponse à "One-liner pour répertorier récursivement les répertoires dans Ruby?" .
Cela fonctionne pour moi:
Si vous ne voulez pas de fichiers cachés [1], utilisez 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 }
Maintenant, Dir.entries renverra des fichiers cachés, et vous n'avez pas besoin de l'astérisme générique (vous pouvez simplement passer la variable avec le nom du répertoire), mais il renverra directement le nom de base, donc les fonctions File.xxx ne fonctionneront pas .
# 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
sous unix, je ne connais pas Windows
Dans Ruby 2.5, vous pouvez maintenant utiliser Dir.children
. Il obtient les noms de fichiers sous forme de tableau à l'exception de "." et ".."
Exemple:
Dir.children("testdir") #=> ["config.h", "main.rb"]
Personnellement, j'ai trouvé cela le plus utile pour boucler sur des fichiers dans un dossier, pour une sécurité prospective:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
Ceci est une solution pour rechercher des fichiers dans un répertoire:
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
Tout en obtenant tous les noms de fichiers dans un répertoire, cet extrait peut être utilisé pour rejeter à la fois les répertoires [ .
, ..
] et les fichiers cachés qui commencent par un.
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
Dir.entries
renvoie des noms de fichiers locaux, pas des chemins de fichiers absolus. D'un autre côté, File.directory?
attend un chemin de fichier absolu. Ce code ne fonctionne pas comme prévu.
ce code renvoie uniquement les noms de fichiers avec leur extension (sans chemin global)
Dir.children("/path/to/search/")
C'est ce qui fonctionne pour moi:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
renvoie un tableau de chaînes. Ensuite, nous devons fournir un chemin complet du fichier vers File.file?
, à moins qu'il ne dir
soit égal à notre répertoire de travail actuel. Voilà pourquoi ça File.join()
.
Vous pouvez également utiliser Rake::FileList
(à condition que vous ayez une rake
dépendance):
FileList.new('lib/*') do |file|
p file
end
Selon l'API:
Les listes de fichiers sont paresseuses. Lorsqu'on lui donne une liste de modèles glob pour les fichiers possibles à inclure dans la liste de fichiers, au lieu de rechercher les structures de fichiers pour trouver les fichiers, une FileList contient le modèle pour une utilisation ultérieure.
Si vous souhaitez obtenir un tableau de noms de fichiers, y compris des liens symboliques , utilisez
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
ou même
Dir.new('/path/to/dir').reject { |f| File.directory? f }
et si vous voulez vous passer de liens symboliques , utilisez
Dir.new('/path/to/dir').select { |f| File.file? f }
Comme indiqué dans d'autres réponses, utilisez Dir.glob('/path/to/dir/**/*')
plutôt que Dir.new('/path/to/dir')
si vous souhaitez obtenir tous les fichiers de manière récursive.
*.*
En plus des suggestions de ce fil, je voulais mentionner que si vous devez également renvoyer des fichiers dot (.gitignore, etc.), avec Dir.glob, vous devrez inclure un indicateur comme Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
suit :
Par défaut, Dir.entries inclut des fichiers de points, ainsi que les répertoires parents actuels.
Pour toute personne intéressée, j'étais curieux de voir comment les réponses ici se comparaient les unes aux autres en temps d'exécution, voici les résultats contre une hiérarchie profondément imbriquée. Les trois premiers résultats sont non récursifs:
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)
Ceux-ci ont été générés avec le script d'analyse comparative suivant:
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
Les différences dans le nombre de fichiers sont dues à l' Dir.entries
inclusion de fichiers cachés par défaut. Dir.entries
a fini par prendre un peu plus de temps dans ce cas en raison de la nécessité de reconstruire le chemin absolu du fichier pour déterminer si un fichier était un répertoire, mais même sans cela, cela prenait toujours plus de temps que les autres options du cas récursif. Tout cela utilisait ruby 2.5.1 sur OSX.
Une façon simple pourrait être:
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
renvoie les chemins relatifs du fichier depuis le répertoire et tous les sous-répertoires
Dans un contexte IRB, vous pouvez utiliser ce qui suit pour obtenir les fichiers dans le répertoire actuel:
file_names = `ls`.split("\n")
Vous pouvez également faire fonctionner cela sur d'autres répertoires:
file_names = `ls ~/Documents`.split("\n")