2010-03-24 13 views
250

¿Cómo escribo un bucle en ruby ​​para poder ejecutar un bloque de código en cada archivo?Iterar a través de cada archivo en un directorio

Soy nuevo en ruby, y he llegado a la conclusión de que la forma de hacerlo es hacer cada ciclo.
El archivo ruby ​​se ejecutará desde un directorio diferente al directorio por el que quiero pasar.

He intentado el Dir.foreach y no pude hacerlo funcionar.

+2

¿Puede especificar qué sucedió cuando intentó que funcionara? ¿Qué código exacto probaste (o el fragmento relevante, si es largo)? ¿Qué mensajes de error obtuviste? 'Dir.foreach' funciona para iterar sobre los contenidos de un directorio, por lo que algo más está sucediendo. – Telemachus

+3

Si solo desea archivos dentro de su directorio, no olvide probar los archivos al iterar sobre el contenido del directorio: 'do_something_with (entrada) if File.file? (Entrada)' –

+3

Use ''img/*. {Jpg, png, gif, jpeg} ''para tomar múltiples extensiones. –

Respuesta

22
Dir.foreach("/home/mydir") do |fname| 
    puts fname 
end 
+1

Alternativamente use Dir # [] o Dir # glob –

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

Además de Dir.new ('/ my/dir') también hay Dir.entries ('/ my/dir') pero Dir.foreach() es un poco más sucinto. –

+4

@ Z.E.D. También 'Dir.foreach' itera mientras' Dir.entries' construye toda la matriz al mismo tiempo. Entonces, si el directorio es inmenso, tendrá menos memoria. (No suele ser un gran problema, probablemente, pero aún así ...) – Telemachus

391

Como han dicho otros, Dir.foreach es una buena opción aquí. Sin embargo, tenga en cuenta que Dir.entries y Dir.foreach siempre mostrarán . y .. (los directorios actuales y principales). En general, usted no va a querer trabajar en ellos, por lo que puede hacer algo como esto:

Dir.foreach('/path/to/dir') do |item| 
    next if item == '.' or item == '..' 
    # do work on real items 
end 

Dir.foreach y Dir.entries también muestran todos los elementos del directorio - ocultos y no ocultos por igual. A menudo, esto es lo que desea, pero si no lo es, debe hacer algo para omitir los archivos y directorios ocultos.

Alternativamente, es posible que desee ver en Dir.glob que proporciona sencilla coincidencia de comodines:

Dir.glob('/path/to/dir/*.rb') do |rb_file| 
    # do work on files ending in .rb in the desired directory 
end 
+11

Utilice 'Dir.foreach' si el directorio contiene una gran cantidad de archivos. – Tilo

+4

gracias! Pequeño mod para hacerlo aún mejor: 'next if File.directory? item' –

+0

@ mr.buttons Eso no siempre hará lo correcto. Algunas veces la gente quiere trabajar en * directorios * y también en archivos. Di un código para evitar los listados especiales para '.' o' ..' porque la gente casi siempre quiere ignorar esos dos. – Telemachus

11

La biblioteca hallazgo está diseñado para esta tarea específica: http://stdlib.rubyonrails.org/libdoc/find/rdoc/index.html

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

Este es un rubí norma biblioteca, por lo que debería estar disponible

+1

'File.find' baja recursivamente tanto como puede, comenzando desde cualquier camino que le des. No estoy seguro de que eso sea lo que quiere el OP. – Telemachus

+0

Parece que no tengo acceso a ese método - Find.find? ¿Debo descargar una biblioteca para incluir esta funcionalidad? –

+0

@ user470184: "Buscar" es una biblioteca de ruby ​​estándar y debe estar disponible con la instalación de ruby ​​predeterminada. Sin embargo, debe "requerir" encontrar "antes de poder usarlo. – Faisal

91

Este es mi método favorito para ser fácil para que diga:

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

e incluso se puede extender esto a trabajar en todos los archivos en subdirectorios:

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

Dir tiene una sintaxis también más corta para obtener una matriz de todos los archivos del directorio:

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

¿Qué en este código impide que los directorios también se utilicen con las iteraciones de' fname'? –

2

Me gusta este, que no se ha mencionado anteriormente.

require 'pathname' 

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

La ventaja es que se obtiene un objeto de nombre de camino en lugar de una cadena, que se pueden hacer cosas útiles con y atravesar más.

Cuestiones relacionadas