Quero obter todos os nomes de arquivos de uma pasta usando Ruby.
Quero obter todos os nomes de arquivos de uma pasta usando Ruby.
Respostas:
Você também tem a opção de atalho de
Dir["/path/to/search/*"]
e se você deseja encontrar todos os arquivos Ruby em qualquer pasta ou subpasta:
Dir["/path/to/search/**/*.rb"]
./...
ao invés de~/
./
significa o diretório atual, enquanto que /
é o ponto de montagem raiz e ~/
o diretório inicial do usuário. Se você mover o projeto inteiro para outro lugar, o primeiro funcionará, mas os outros dois provavelmente não.
Dir.entries(folder)
exemplo:
Dir.entries(".")
Fonte: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
poderia ter sido mencionado, por exemplo), não há nada para impedir que outra pessoa poste uma resposta realmente boa. 'Claro, eu sou mais um 'copo meio cheio' espécie de um cara ...
Dir
raramente, e toda vez que preciso preciso ler a documentação. Postei minha pergunta e resposta aqui para encontrá-la mais tarde e talvez até ajudar alguém com a mesma pergunta. Acho que ouvi no podcast da SO que não há nada de errado com esse comportamento. Se você tiver uma resposta melhor, poste-a. Publiquei o que sei, não sou um ninja Ruby. Aceito regularmente respostas com mais votos.
Dir[]
ou Dir.glob
quando o argumento é uma variável. Quando path = '/tmp'
, compare: Dir.glob("#{path}/*")
vs Dir.entries(path)
. Os valores de retorno são um pouco diferentes (".", ".."), mas o último é mais fácil de entender rapidamente.
Os seguintes trechos mostra exatamente o nome dos arquivos dentro de um diretório, subdiretórios pular e "."
, ".."
pastas pontilhadas:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
para obter um significado mais claro e uma sintaxe mais curta.
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
está funcionando, mas File.file?
não está.
.reject {|f| File.directory? f}
parece mais limpo do que .select{|f| !File.directory? f}
. Ah, e agora eu vejo o primeiro comentário ... também é bom.
Para obter todos os arquivos (somente arquivos estritamente) recursivamente:
Dir.glob('path/**/*').select{ |e| File.file? e }
Ou qualquer coisa que não seja um diretório ( File.file?
rejeitaria arquivos não regulares):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Usar Find#find
um método de pesquisa baseado em padrões como Dir.glob
é realmente melhor. Veja esta resposta em "Lista única para listar recursivamente diretórios em Ruby?" .
Isso funciona para mim:
Se você não deseja arquivos 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 }
Agora, Dir.entries retornará arquivos ocultos e você não precisará do curinga asterix (basta passar a variável com o nome do diretório), mas retornará o nome da base diretamente, para que as funções File.xxx não funcionem .
# 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
no unix, eu não sei sobre o Windows
Agora, no Ruby 2.5, você pode usar Dir.children
. Ele obtém nomes de arquivos como uma matriz, exceto por "." e ".."
Exemplo:
Dir.children("testdir") #=> ["config.h", "main.rb"]
Pessoalmente, achei isso o mais útil para fazer loop sobre arquivos em uma pasta, com segurança no futuro:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
Esta é uma solução para encontrar arquivos em um diretório:
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
Ao obter todos os nomes de arquivo em um diretório, esse trecho pode ser usado para rejeitar os diretórios [ .
, ..
] e os arquivos ocultos que começam com um.
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
Dir.entries
retorna nomes de arquivos locais, não caminhos de arquivo absolutos. Por outro lado, File.directory?
espera um caminho de arquivo absoluto. Este código não funciona conforme o esperado.
esse código retorna apenas nomes de arquivos com sua extensão (sem um caminho global)
Dir.children("/path/to/search/")
Isto é o que funciona para mim:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
retorna uma matriz de seqüências de caracteres. Então, temos que fornecer um caminho completo do arquivo para File.file?
, a menos que dir
seja igual ao nosso diretório de trabalho atual. É por isso que isso File.join()
.
Você também pode querer usar Rake::FileList
(desde que tenha rake
dependência):
FileList.new('lib/*') do |file|
p file
end
De acordo com a API:
As listas de arquivos são preguiçosas. Quando é fornecida uma lista de padrões globais para a inclusão de possíveis arquivos na lista de arquivos, em vez de procurar nas estruturas de arquivos para encontrar os arquivos, um FileList mantém o padrão para uso posterior.
Se você deseja obter uma variedade de nomes de arquivos, incluindo links simbólicos , use
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
ou mesmo
Dir.new('/path/to/dir').reject { |f| File.directory? f }
e se você quiser ficar sem links simbólicos , use
Dir.new('/path/to/dir').select { |f| File.file? f }
Conforme mostrado em outras respostas, use em Dir.glob('/path/to/dir/**/*')
vez de Dir.new('/path/to/dir')
se desejar obter todos os arquivos recursivamente.
*.*
Além das sugestões neste tópico, eu gostaria de mencionar que, se você também precisar retornar arquivos de ponto (.gitignore, etc), com o Dir.glob, será necessário incluir um sinalizador da seguinte maneira:
Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
Por padrão, Dir.entries inclui arquivos de ponto, bem como os diretórios pai atuais.
Para qualquer pessoa interessada, fiquei curioso para saber como as respostas aqui se comparavam em tempo de execução, eis os resultados contra uma hierarquia profundamente aninhada. Os três primeiros resultados são não 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)
Eles foram gerados com o seguinte script de benchmarking:
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
As diferenças nas contagens de arquivos são devidas à Dir.entries
inclusão de arquivos ocultos por padrão. Dir.entries
acabou demorando um pouco mais nesse caso, devido à necessidade de reconstruir o caminho absoluto do arquivo para determinar se um arquivo era um diretório, mas mesmo assim ele ainda estava demorando consistentemente mais do que as outras opções no caso recursivo. Isso tudo estava usando o ruby 2.5.1 no OSX.
Uma maneira simples pode 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
retorna os caminhos relativos do arquivo do diretório e de todos os subdiretórios
Em um contexto de IRB, você pode usar o seguinte para obter os arquivos no diretório atual:
file_names = `ls`.split("\n")
Você também pode fazer isso funcionar em outros diretórios:
file_names = `ls ~/Documents`.split("\n")