web-dev-qa-db-fra.com

Obtenir les noms de tous les fichiers d'un dossier avec Ruby

Je veux obtenir tous les noms de fichiers d'un dossier à l'aide de Ruby.

322
Željko Filipin

Vous avez également l'option de raccourci de

Dir["/path/to/search/*"]

et si vous voulez trouver tous les fichiers Ruby dans un dossier ou un sous-dossier:

Dir["/path/to/search/**/*.rb"]
488
Ian Eccles
Dir.entries(folder)

exemple:

Dir.entries(".")

Source: http://Ruby-doc.org/core/classes/Dir.html#method-c-entries

156
Željko Filipin

Les extraits suivants montrent exactement le nom des fichiers dans un répertoire, ignorant les sous-répertoires et les dossiers ".", "..":

Dir.entries("your/folder").select {|f| !File.directory? f}
87
Emiliano Poggi

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 normaux):

_Dir.glob('path/**/*').reject{ |e| File.directory? e }
_

Solution alternative

L'utilisation de Find#find sur une méthode de recherche basée sur un modèle telle que _Dir.glob_ est en fait préférable. Voir cette réponse à "Une ligne pour la liste récursive des répertoires en Ruby?" .

32
konsolebox

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 retournera les fichiers cachés, et vous n’avez pas besoin de l’astérisque (vous pouvez simplement passer la variable avec le nom du répertoire), mais le nom de base sera retourné directement. Les fonctions .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

14
user1115652

Personnellement, j’ai trouvé cela le plus utile pour boucler sur les fichiers d’un dossier, en toute sécurité:

Dir['/etc/path/*'].each do |file_name|
  next if File.directory? file_name 
end
8
mr.buttons

C'est une solution pour trouver 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
8
gilcierweb

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"]

http://Ruby-doc.org/core-2.5.0/Dir.html#method-c-children

5
Mario Pérez

Tout en obtenant tous les noms de fichiers dans un répertoire, cet extrait peut être utilisé pour rejeter les répertoires [., ..] et les fichiers cachés commençant par ..

files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
4
Lahiru

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 à File.file?, sauf si dir est égal à notre répertoire de travail actuel. C'est pourquoi cette File.join().

3
yegor256

Vous pouvez aussi vouloir utiliser Rake::FileList (à condition que vous ayez la dépendance rake:):

FileList.new('lib/*') do |file|
  p file
end

Selon l'API:

FileLists sont paresseux. Lorsqu'une liste de modèles globaux permettant d'inclure des fichiers dans la liste de fichiers est fournie, au lieu de rechercher dans les structures de fichiers pour rechercher les fichiers, une liste de fichiers conserve le modèle pour une utilisation ultérieure.

https://docs.Ruby-lang.org/fr/2.1.0/Rake/FileList.html

2
Artur Beljajev

En plus des suggestions de ce fil de discussion, je voulais mentionner que si vous devez également renvoyer des fichiers points (.gitignore, etc.), avec Dir.glob, vous devez également inclure un indicateur: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) By Par défaut, Dir.entries inclut les fichiers de points, ainsi que les répertoires parents actuels.

Pour ceux qui étaient intéressés, j'étais curieux de voir comment les réponses se comparaient les unes aux autres en temps d'exécution, voici les résultats par rapport à 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)

Celles-ci ont été générées 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 de nombre de fichiers sont dues à Dir.entries, y compris les fichiers cachés par défaut. Dir.entries a pris un peu plus de temps dans ce cas, car il a fallu reconstruire le chemin absolu du fichier pour déterminer si un fichier était un répertoire, mais même si cela prenait toujours plus de temps que les autres options de la liste. cas récursif. Tout cela utilisait Ruby 2.5.1 sur OSX.

1
Ben
Dir.new('/home/user/foldername').each { |file| puts file }
1
Ashwin

Si vous voulez 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 aller sans liens symboliques, utilisez

Dir.new('/path/to/dir').select { |f| File.file? f }

Comme indiqué dans les autres réponses, utilisez Dir.glob('/path/to/dir/**/*') au lieu de Dir.new('/path/to/dir') si vous souhaitez obtenir tous les fichiers de manière récursive.

1
Mikhail Vasin
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

0
punksta

Dans un contexte IRB, vous pouvez utiliser les éléments suivants pour obtenir les fichiers du répertoire actuel:

file_names = `ls`.split("\n")

Vous pouvez aussi faire en sorte que cela fonctionne sur d'autres répertoires:

file_names = `ls ~/Documents`.split("\n")
0

ce code ne renvoie que les noms de fichiers avec leur extension (sans chemin global)

Dir.children("/path/to/search/")

Un moyen simple pourrait être:

dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}

files.each do |f|
    puts f
end
0
Sebastian Capone