2009-11-05 28 views
12

necesito leer un archivo en trozos MB, ¿hay una forma más limpia de hacer esto en Ruby:Leer un archivo en trozos en Ruby

FILENAME="d:\\tmp\\file.bin" 
MEGABYTE = 1024*1024 
size = File.size(FILENAME) 
open(FILENAME, "rb") do |io| 
    read = 0 
    while read < size 
    left = (size - read) 
    cur = left < MEGABYTE ? left : MEGABYTE 
    data = io.read(cur) 
    read += data.size 
    puts "READ #{cur} bytes" #yield data 
    end 
end 

Respuesta

19

Adaptado de la página de Ruby Cookbook 204:

FILENAME = "d:\\tmp\\file.bin" 
MEGABYTE = 1024 * 1024 

class File 
    def each_chunk(chunk_size = MEGABYTE) 
    yield read(chunk_size) until eof? 
    end 
end 

open(FILENAME, "rb") do |f| 
    f.each_chunk { |chunk| puts chunk } 
end 

Descargo de responsabilidad: Soy un novato de rubí y no he probado esto.

+0

Sí, esto funciona. Sin embargo, pensé que IO.read arrojaría si el número de bytes restantes era menor que el tamaño del fragmento. Pensé eso porque había leído sobre IO.readbyte, que lanzará TruncatedDataError. Parece que NO se aplica a la lectura. Un oversite de mi parte. Gracias! – teleball

-1
FILENAME="d:/tmp/file.bin" 

class File 
    MEGABYTE = 1024*1024 

    def each_chunk(chunk_size=MEGABYTE) 
    yield self.read(chunk_size) until self.eof? 
    end 
end 

open(FILENAME, "rb") do |f| 
    f.each_chunk {|chunk| puts chunk } 
end 

Funciona, mbarkhau. Acabo de mover la definición constante a la clase File y agregué un par de "selfs" para mayor claridad.

+2

No usaría la constante extra MEGABYTE, en cambio: 'def each_chunk (chunk_size = 2 ** 20)' – asaaki

7

alternativa, si no desea monkeypatch File:

until my_file.eof? 
    do_something_with(my_file.read(bytes)) 
end 

Por ejemplo, la transmisión de un archivo temporal subido en un nuevo archivo:

# tempfile is a File instance 
File.open(new_file, 'wb') do |f| 
    # Read in small 65k chunks to limit memory usage 
    f.write(tempfile.read(2**16)) until tempfile.eof? 
end 
0

Si se echa un vistazo a los documentos de rubí: http://ruby-doc.org/core-2.2.2/IO.html hay una línea que dice así:

IO.foreach("testfile") {|x| print "GOT ", x } 

La única advertencia es. Puesto que, este proceso puede leer el archivo temporal más rápido que la corriente generada, la OMI, una latencia debe ser arrojados en.

IO.foreach("/tmp/streamfile") {|line| 
    ParseLine.parse(line) 
    sleep 0.3 #pause as this process will discontine if it doesn't allow some buffering 
} 
1

Usted puede utilizar IO#each(sep, limit), y establecer sep-nil o cadena vacía, por ejemplo, :

chunk_size = 1024 
File.open('/path/to/file.txt').each(nil, chunk_size) do |chunk| 
    puts chunk 
end 
+0

Eso es simplemente incorrecto. –

+1

@EricDuminil Gracias por recordarme, olvidé el argumento de septiembre. Debería leer un archivo en fragmentos ahora. –

Cuestiones relacionadas