2011-11-02 24 views
9

Soy nuevo en Ruby (ser un desarrollador de Java) y trato de implementar un método (oh, lo siento, una función) que recupere y ceda todos los archivos en los subdirectorios recursivamente.lista de archivos recursivos en Ruby

vez implementado como:

def file_list_recurse(dir) 
    Dir.foreach(dir) do |f| 
    next if f == '.' or f == '..' 
    f = dir + '/' + f 
    if File.directory? f 
     file_list_recurse(File.absolute_path f) { |x| yield x } 
    else 
     file = File.new(f) 
     yield file 
    end 
    end 
end 

Mis preguntas son:

  1. ¿El File.new realmente abrir un archivo? En Java, el nuevo archivo ("xxx") no ... ¿Debo dar alguna estructura para poder consultar la información del archivo (ctime, tamaño, etc.) de lo que sería en Ruby?
  2. {| x | rendimiento x} me parece un poco extraño, ¿está bien hacer rendimientos de funciones recursivas como esa, o hay alguna forma de evitarlo?
  3. ¿Hay alguna forma de evitar la búsqueda de '.' y '..' en cada iteración?
  4. ¿Hay una mejor manera de implementar esto?

Gracias

PS: el uso de muestras de mi método es algo como esto:

curr_file = nil 

file_list_recurse('.') do |file| 
    curr_file = file if curr_file == nil or curr_file.ctime > file.ctime 
end 

puts curr_file.to_path + ' ' + curr_file.ctime.to_s 

(que sería conseguir que el archivo más antiguo del árbol)

= =========

Así que, gracias a @buruza emon Descubrí la gran función Dir.glob que me salvó un par de líneas de código. Además, gracias a @Casper He encontrado a cabo el método File.stat, lo que hizo que mi carrera función dos veces más rápido que con File.new

Al final mi código está buscando algo como esto:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 

=====

Por defecto Dir.glob ignora los nombres de archivo a partir de un punto (que se considera que se 'oculta' en * nix), por lo que es muy importante para añadir el segundo argumento de archivos :: FNM_DOTMATCH

Respuesta

5

esta cosa me dice que la posibilidad de aceptar una respuesta, espero que no le importaría contestarme a mí mismo:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 
2

Puede usar elincorporadomódulo find método.

11

¿Qué tal esto?

puts Dir['**/*.*'] 
+0

Eso es genial!Pero produce un conjunto de objetos String. Lo que estoy buscando es una función que produzca una estructura similar a un archivo para poder hacer mis propios cálculos en función de eso. Encontrar el archivo más grande, el ctime más antiguo, etc. –

+0

Dir ['.'] No acepta un bloque. ¡Pero Dir.glob sí! Responde a mis preguntas, a excepción de la pregunta n. ° –

5

De acuerdo con los documentos File.new abre el archivo. Es posible que desee utilizar File.stat en su lugar, que reúne estadísticas relacionadas con archivos en un objeto consultable. Pero tenga en cuenta que las estadísticas se recopilan en el punto de creación. No cuando llamas a los métodos de consulta como ctime.

Ejemplo:

Dir['**/*'].select { |f| File.file?(f) }.map { |f| File.stat(f) } 
+1

File.stat, irónicamente, no proporciona el nombre del archivo, por lo que no puedo usarlo como un objeto de datos para devolver desde mi método. Además, tengo un árbol de 200,000 archivos. Al ejecutar los resultados de su ejemplo, el proceso de ruby ​​crece por encima de 60 Mb, mientras que ejecutar mi método (incluso con File.new) nunca hace que el rubí supere los 6 Mb. (Estoy probando con reloj -n 0,1 "ps ax -o comm, rss | grep ruby ​​>>/tmp/q"). Pero la línea de código de muestra parece genial ;-) –

Cuestiones relacionadas