2009-11-05 19 views
12

muszę odczytać pliku w MB kawałki, czy istnieje przejrzysty sposób to zrobić w Ruby:Czytaj plik w kawałkach w 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 

Odpowiedz

19

Adaptacja strony 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 

Nota prawna: Jestem początkującym użytkownikiem ruby ​​i nie testowałem tego.

+0

Tak, to działa. Jednak myślałem, że IO.read rzuciłby, gdyby pozostała liczba bajtów była mniejsza niż rozmiar porcji. Pomyślałem, że ponieważ przeczytałem o IO.readbyte, który rzuci TruncatedDataError. Wygląda na to, że NIE odnosi się do odczytu. Oversite z mojej strony. Dzięki! – 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 

To działa, mbarkhau. Właśnie przeniosłem stałą definicję do klasy File i dodałem kilka "self" dla jasności.

+2

Nie używałbym dodatkowej stałej MEGABYTE zamiast: 'def each_chunk (chunk_size = 2 ** 20)' – asaaki

7

Ewentualnie, jeśli nie chcesz monkeypatch File:

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

Na przykład, streaming przesłanego pliku tymczasowego do nowego pliku:

# 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

Jeśli sprawdzeniu docs rubinowe: http://ruby-doc.org/core-2.2.2/IO.html Istnieje linia, która wygląda następująco:

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

Jedyna uwaga zastrzeżona jest. Ponieważ proces ten może odczytać pliku tymczasowego szybciej niż generowanego strumienia, IMO, latencja powinny być rzucony w.

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

Można użyć IO#each(sep, limit) i ustaw sep do nil lub pusty ciąg znaków, na przykład :

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

To po prostu niepoprawne. –

+1

@EricDuminil Dzięki za przypomnienie mi, zapomniałem argumentu sep. Teraz powinien przeczytać fragment w kawałkach. –