Scorrere tutti i file in una directory


274

Come faccio a scrivere un ciclo in ruby ​​in modo da poter eseguire un blocco di codice su ciascun file?

Sono nuovo di Ruby e ho concluso che il modo per farlo è fare ogni ciclo.
Il file ruby ​​verrà eseguito da una directory diversa rispetto alla directory che voglio scorrere.

Ho provato il Dir.foreache non sono riuscito a farlo funzionare.


2
Puoi specificare cosa è successo quando hai provato a farlo funzionare? Quale codice esatto hai provato (o il blocco pertinente, se è lungo)? Quali messaggi di errore hai ricevuto? Dir.foreachfunziona per scorrere i contenuti di una directory, quindi c'è qualcosa di molto in corso.
Telemaco,

3
Se desideri solo file all'interno della tua directory, non dimenticare di testare i file quando si scorre il contenuto della directory: do_something_with(entry) if File.file?(entry)
glenn jackman

3
Utilizzare 'img/*.{jpg,png,gif,jpeg}'per afferrare più estensioni.
Benjamin Crouzier,

Sfortunatamente @ChrisPeters sembra improbabile, dal momento che l'OP non è sul sito da oltre quattro anni.
Joe Kennedy,

Risposte:


430

Come altri hanno già detto, Dir::foreachè una buona opzione qui. Tuttavia, si noti che Dir::foreache Dir::entriesincluderà sempre .e ..(le directory corrente e parent). In genere non vorrai lavorarci sopra, quindi puoi usare Dir::each_childo Dir::children(come suggerito da ma11hew28 ) o fare qualcosa del genere:

Dir.foreach('/path/to/dir') do |filename|
  next if filename == '.' or filename == '..'
  # Do work on the remaining files & directories
end

Dir::foreache Dir::entries(oltre a Dir::each_childe Dir::children) includono anche file e directory nascosti. Spesso questo è quello che vuoi, ma se non lo è, devi fare qualcosa per saltarli.

In alternativa, potresti voler esaminare Dir::globquale fornisce una semplice corrispondenza jolly:

Dir.glob('/path/to/dir/*.rb') do |rb_filename|
  # Do work on files & directories ending in .rb
end

12
Utilizzare Dir.foreachse la directory contiene un numero enorme di file!
Tilo,

5
Grazie! Piccolo mod per renderlo ancora migliore:next if File.directory? item
mr.buttons,

@ mr.buttons Quello non farà sempre la cosa giusta. A volte le persone vogliono lavorare su directory e file. Ho dato il codice per evitare gli elenchi speciali per .o ..perché le persone vogliono quasi sempre ignorare quei due.
Telemaco,

3
@Tilo: solo per interesse, ti interessa spiegare un po 'più in dettaglio perché? :)
mkataja,

11
@mkataja esegue Dir.foreachun'iterazione anziché creare un array (potenzialmente enorme) in primo piano (il che lo Dir.globfa). Quindi, se la directory è davvero enorme, può fare la differenza. In circostanze normali non lo noteresti, ma in condizioni di stress, può assolutamente importare.
Telemaco,

99

Questo è il mio metodo preferito per essere facile da leggere:

Dir.glob("*/*.txt") do |my_text_file|
  puts "working on: #{my_text_file}..."
end

E puoi anche estenderlo per lavorare su tutti i file nei sottodir:

Dir.glob("**/*.txt") do |my_text_file| # note one extra "*"
  puts "working on: #{my_text_file}..."
end

30

Dir ha anche una sintassi più breve per ottenere una matrice di tutti i file dalla directory:

Dir['dir/to/files/*'].each do |fname|
    # do something with fname
end

Cosa in questo codice impedisce alle directory di essere utilizzate anche con fnamele iterazioni?
kayleeFrye_onDeck,

26
Dir.foreach("/home/mydir") do |fname|
  puts fname
end

2
In alternativa, usa Dir # [] o Dir # glob
Ryan Bigg

13

La libreria find è progettata specificamente per questa attività: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

require 'find'
Find.find(path) do |file|
  # process
end

Questa è una libreria ruby ​​standard, quindi dovrebbe essere disponibile


1
File.findscende in modo ricorsivo il più lontano possibile, a partire da qualunque percorso tu gli dia. Non sono sicuro che sia quello che vuole l'OP.
Telemaco,

Non sembra che io abbia accesso a quel metodo: Find.find? Devo scaricare una libreria o includere questa funzionalità?
blue-sky

@utente470184: "Trova" è una libreria ruby ​​standard e dovrebbe essere disponibile con l'installazione ruby ​​predefinita. Tuttavia, è necessario "richiedere 'trova'" prima di poterlo utilizzare.
Faisal,

1
@Faisal Can passo modelli glob come *.rbafind()
Ashhar Hasan

7

Mi piace questo, che non è stato menzionato sopra.

require 'pathname'

Pathname.new('/my/dir').children.each do |path|
    puts path
end

Il vantaggio è che ottieni un oggetto Pathname invece di una stringa, con cui puoi fare cose utili e attraversare ulteriormente.


3
Dir.new('/my/dir').each do |name|
  ...
end

1
Oltre a Dir.new ('/ my / dir') c'è anche Dir.entries ('/ my / dir') ma Dir.foreach () è un po 'più sintetico.
Tin Man,

5
@ZED Esegue inoltre l' Dir.foreachiterazione mentre Dir.entriescrea l'intero array contemporaneamente. Quindi se la directory è immensa, è meno un colpo di memoria. (Di solito non è un grosso problema, probabilmente, ma comunque ...)
Telemaco il

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.