Ottieni nomi di tutti i file da una cartella con Ruby


Risposte:


538

Hai anche l'opzione di scelta rapida di

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

e se vuoi trovare tutti i file Ruby in qualsiasi cartella o sottocartella:

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

5
Oppure puoi fare lo stesso con Dir :: glob ()
Yoann Le Touche,

2
Inoltre, usa ./...piuttosto che~/
Minh Triet il

5
Perché questo è preferito?
BvuRVKyUVlViVIc7,

1
@MinhTriet che cosa fa? Qual è preferibile?
stephenmurdoch,

9
@marflar: ./indica la directory corrente, mentre /è il punto di montaggio principale e ~/la home directory dell'utente. Se sposti l'intero progetto da qualche altra parte, il primo funzionerà, ma gli altri due probabilmente non lo faranno.
mirichan,

170
Dir.entries(folder)

esempio:

Dir.entries(".")

Fonte: http://ruby-doc.org/core/classes/Dir.html#method-c-entries


15
Sembra che stia usando SO per documentare le risposte alle domande che ha appena fatto. Una specie di promemoria, suppongo. Non riesco a vedere molto di sbagliato in questo - dopo tutto, anche se questo è un po 'incompleto ( Dir#globforse sarebbe stato menzionato, per esempio) non c'è nulla che impedisca a qualcun altro di pubblicare una risposta davvero buona. "Certo, sono per lo più una specie di" mezzo bicchiere pieno "di un ragazzo ...
Mike Woodhouse,

1
@ Mike: nel grande schema delle cose, probabilmente non è un grosso problema. E come dici se le domande e le risposte erano buone, potrebbe essere un vantaggio generale per il sito. Ma qui sia la domanda che la risposta sono così minime che non sembra particolarmente utile.
Telemaco,

17
@Telemachus lo uso Dirraramente e ogni volta che ne ho bisogno devo leggere la documentazione. Ho pubblicato la mia domanda e la risposta qui in modo da poterla trovare in seguito, e forse anche aiutare qualcuno con la stessa domanda. Penso di aver sentito al podcast SO che non c'è niente di sbagliato in questo comportamento. Se hai una risposta migliore, per favore pubblicala. Ho pubblicato ciò che so, non sono un ninja di Ruby. Accetto regolarmente le risposte con il maggior numero di voti.
Željko Filipin,

Questa può essere un'opzione migliore di Dir[]o Dir.globquando l'argomento è una variabile. Quando path = '/tmp', confrontare: Dir.glob("#{path}/*")vs Dir.entries(path). I valori di ritorno sono leggermente diversi (".", ".."), ma quest'ultimo è più facile da individuare a colpo d'occhio.
Benjamin Oakes,

92

I seguenti frammenti mostra esattamente il nome dei file all'interno di una directory, sottodirectory saltare e ".", ".."cartelle tratteggiate:

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

19
Può anche fare ...select {|f| File.file? f}per un significato più chiaro e una sintassi più breve.
Automatico

2
@squixy L'hai scritto correttamente ?:Dir.entries("your/folder").select {|f| File.file? f}
Automatico

9
Sì. !File.directory?funziona ma File.file?no.
Kamil Lelonek,

2
@squixy Ho avuto lo stesso problema, nel mio caso ho bisogno di fornire il percorso completo non solo il nome del file restituito da Dir.foreach
TheLukeMcCarthy

6
.reject {|f| File.directory? f}sembra più pulito di .select{|f| !File.directory? f}. Oh, e ora vedo il primo commento ... anche buono.
Ian,


18

Questo funziona per me:

Se non vuoi file nascosti [1], usa 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 }

Ora Dir.entries restituirà i file nascosti e non è necessario il carattere jolly asterix (puoi semplicemente passare la variabile con il nome della directory), ma restituirà direttamente il nome di base, quindi le funzioni File.xxx non funzioneranno .

# 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] .dotfilesu unix, non conosco Windows



9

Personalmente, ho trovato questo il più utile per eseguire il looping dei file in una cartella, sicurezza in avanti:

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

9

Questa è una soluzione per trovare i file in una directory:

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

6

Mentre si ottengono tutti i nomi di file in una directory, questo frammento può essere utilizzato per rifiutare sia le directory [ ., ..] sia i file nascosti che iniziano con un.

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

Dir.entriesrestituisce nomi di file locali, non percorsi di file assoluti. D'altro canto, si File.directory?aspetta un percorso file assoluto. Questo codice non funziona come previsto.
Nathan,

È strano che il codice non funzioni nel tuo caso. Dato che questo è un codice che ho usato in un'app live che funziona perfettamente. Ricontrollerò il mio codice e
pubblicherò

1
@Nathan Vedi la mia risposta per una spiegazione


4

Questo è ciò che funziona per me:

Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }

Dir.entriesrestituisce una matrice di stringhe. Quindi, dobbiamo fornire un percorso completo del file File.file?, a meno che non dirsia uguale alla nostra directory di lavoro corrente. Ecco perché questo File.join().


1
Devi escludere "." e ".." dalle voci
Edgar Ortega

3

Potresti anche voler usare Rake::FileList(purché tu abbia una rakedipendenza):

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

Secondo l'API:

Gli elenchi di file sono pigri. Quando viene fornito un elenco di schemi glob per possibili file da includere nell'elenco dei file, invece di cercare le strutture dei file per trovare i file, un FileList contiene il modello per un uso successivo.

https://docs.ruby-lang.org/en/2.1.0/Rake/FileList.html


1

Se vuoi ottenere una matrice di nomi di file inclusi i collegamenti simbolici , usa

Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }

o anche

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

e se vuoi andare senza symlink , usa

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

Come mostrato in altre risposte, utilizzare Dir.glob('/path/to/dir/**/*')invece di Dir.new('/path/to/dir')se si desidera ottenere tutti i file in modo ricorsivo.


O semplicemente usa*.*
Richard Peck il

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

1

Oltre ai suggerimenti in questo thread, vorrei menzionare che se è necessario restituire anche file dot (.gitignore, ecc.), Con Dir.glob è necessario includere un flag in questo modo: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) per impostazione predefinita, Dir.entries include file dot e directory correnti di un genitore.

Per chiunque fosse interessato, ero curioso di sapere come le risposte qui comparate tra loro in tempo di esecuzione, ecco i risultati contro la gerarchia profondamente annidata. I primi tre risultati non sono ricorsivi:

       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)

Questi sono stati generati con il seguente script di 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

Le differenze nel conteggio dei file sono dovute Dir.entriesall'inclusione di file nascosti per impostazione predefinita. Dir.entriesha finito per impiegare un po 'più tempo in questo caso a causa della necessità di ricostruire il percorso assoluto del file per determinare se un file era una directory, ma anche senza quello stava ancora impiegando costantemente più tempo rispetto alle altre opzioni nel caso ricorsivo. Tutto questo stava usando ruby ​​2.5.1 su OSX.


1

Un modo semplice potrebbe essere:

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

files.each do |f|
    puts f
end

0
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

restituisce i percorsi relativi del file dalla directory e da tutte le sottodirectory


0

In un contesto IRB, è possibile utilizzare quanto segue per ottenere i file nella directory corrente:

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

Puoi farlo funzionare anche su altre directory:

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

Questa soluzione ha funzionato per me poiché ho una soluzione legacy con la vecchia versione ruby ​​che non supporta il comando Dir.children
Ciprian Dragoe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.