Quiero obtener todos los nombres de archivo de una carpeta con Ruby.
Quiero obtener todos los nombres de archivo de una carpeta con Ruby.
Respuestas:
También tiene la opción de acceso directo de
Dir["/path/to/search/*"]
y si desea encontrar todos los archivos Ruby en cualquier carpeta o subcarpeta:
Dir["/path/to/search/**/*.rb"]
./...
lugar de~/
./
significa el directorio actual, mientras que /
es el punto de montaje raíz y ~/
es el directorio de inicio del usuario. Si mueve todo el proyecto a otro lugar, el primero funcionará, pero los otros dos probablemente no.
Dir.entries(folder)
ejemplo:
Dir.entries(".")
Fuente: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
tal vez podría haber sido mencionado, por ejemplo), no hay nada que evite que alguien más publique una Respuesta realmente buena. 'Por supuesto, soy sobre todo un 'vaso medio lleno' una especie de chico ...
Dir
raramente, y cada vez que lo necesito tengo que leer la documentación. He publicado mi pregunta y respuesta aquí para poder encontrarla más tarde, y tal vez incluso ayudar a alguien con la misma pregunta. Creo que he escuchado en el podcast SO que no hay nada de malo en este comportamiento. Si tiene una mejor respuesta, publíquela. He publicado lo que sé, no soy un ninja Ruby. Regularmente acepto respuestas con la mayoría de los votos.
Dir[]
o Dir.glob
cuando el argumento es una variable. Cuando path = '/tmp'
, comparar: Dir.glob("#{path}/*")
vs Dir.entries(path)
. Los valores de retorno son ligeramente diferentes (".", ".."), pero este último es más fácil de asimilar a simple vista.
Los siguientes fragmentos de muestra exactamente el nombre de los archivos dentro de un directorio, subdirectorios y saltar "."
, ".."
carpetas de puntos:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
para un significado más claro y una sintaxis más corta.
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
está funcionando pero File.file?
no.
.reject {|f| File.directory? f}
parece más limpio que .select{|f| !File.directory? f}
. Ah, y ahora veo el primer comentario ... también bueno.
Para obtener todos los archivos (estrictamente solo archivos) de forma recursiva:
Dir.glob('path/**/*').select{ |e| File.file? e }
O cualquier cosa que no sea un directorio ( File.file?
rechazaría archivos no regulares):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Usar Find#find
más de un método de búsqueda basado en patrones como en Dir.glob
realidad es mejor. Vea esta respuesta a "One-liner para enumerar directorios recursivamente en Ruby? .
Esto funciona para mi:
Si no desea archivos ocultos [1], use 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 }
Ahora, Dir.entries devolverá archivos ocultos, y no necesita el asterisco comodín (solo puede pasar la variable con el nombre del directorio), pero devolverá el nombre base directamente, por lo que las funciones File.xxx no funcionarán .
# 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
en Unix, no sé sobre Windows
En Ruby 2.5 ahora puedes usar Dir.children
. Obtiene los nombres de archivo como una matriz, excepto "." y ".."
Ejemplo:
Dir.children("testdir") #=> ["config.h", "main.rb"]
Personalmente, encontré que esto es lo más útil para recorrer los archivos en una carpeta, con miras a la seguridad:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
Esta es una solución para buscar archivos en un directorio:
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
Al obtener todos los nombres de archivo en un directorio, este fragmento se puede utilizar para rechazar los directorios [ .
, ..
] y los archivos ocultos que comienzan con un.
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
Dir.entries
devuelve nombres de archivos locales, no rutas de archivos absolutas. Por otro lado, File.directory?
espera una ruta de archivo absoluta. Este código no funciona como se esperaba.
este código solo devuelve nombres de archivo con su extensión (sin una ruta global)
Dir.children("/path/to/search/")
Esto es lo que funciona para mí:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
devuelve una matriz de cadenas. Luego, tenemos que proporcionar una ruta completa del archivo File.file?
, a menos que dir
sea igual a nuestro directorio de trabajo actual. Por eso esto File.join()
.
También es posible que desee utilizar Rake::FileList
(siempre que tenga rake
dependencia):
FileList.new('lib/*') do |file|
p file
end
De acuerdo con la API:
Las listas de archivos son flojas. Cuando se le proporciona una lista de patrones globales para posibles archivos que se incluirán en la lista de archivos, en lugar de buscar en las estructuras de archivos para encontrar los archivos, una FileList contiene el patrón para su uso posterior.
Si desea obtener una variedad de nombres de archivos, incluidos enlaces simbólicos , use
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
o incluso
Dir.new('/path/to/dir').reject { |f| File.directory? f }
y si quieres ir sin enlaces simbólicos , usa
Dir.new('/path/to/dir').select { |f| File.file? f }
Como se muestra en otras respuestas, utilice en Dir.glob('/path/to/dir/**/*')
lugar de Dir.new('/path/to/dir')
si desea obtener todos los archivos de forma recursiva.
*.*
Además de las sugerencias en este hilo, quería mencionar que si también necesita devolver archivos de puntos (.gitignore, etc.), con Dir.glob necesitaría incluir un indicador como tal:
Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
De manera predeterminada, las entradas de Dir. incluye archivos de puntos, así como los directorios principales actuales.
Para cualquier persona interesada, tenía curiosidad de cómo las respuestas aquí se comparaban entre sí en tiempo de ejecución, aquí estaban los resultados contra una jerarquía profundamente anidada. Los primeros tres resultados no son recursivos:
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)
Estos se generaron con el siguiente script de evaluación comparativa:
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
Las diferencias en el recuento de archivos se deben a la Dir.entries
inclusión de archivos ocultos de forma predeterminada. Dir.entries
terminó tomando un poco más de tiempo en este caso debido a la necesidad de reconstruir la ruta absoluta del archivo para determinar si un archivo era un directorio, pero incluso sin eso todavía tardaba mucho más que las otras opciones en el caso recursivo. Todo esto estaba usando ruby 2.5.1 en OSX.
Una forma simple podría ser:
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
devuelve las rutas relativas del archivo desde el directorio y todos los subdirectorios
En un contexto IRB, puede usar lo siguiente para obtener los archivos en el directorio actual:
file_names = `ls`.split("\n")
También puede hacer que esto funcione en otros directorios:
file_names = `ls ~/Documents`.split("\n")