2009-11-05 23 views
12

tôi cần phải đọc một tập tin trong khối MB, là có một cách sạch hơn để làm điều này trong Ruby:Đọc một tập tin trong khối trong 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 

Trả lời

19

Được chuyển thể từ trang của 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 

Tuyên bố từ chối trách nhiệm: Tôi là người mới chơi ruby ​​và chưa thử nghiệm điều này.

+0

Có, tính năng này hoạt động. Tuy nhiên, tôi nghĩ rằng IO.read sẽ ném nếu số byte còn lại nhỏ hơn kích thước chunk. Tôi nghĩ rằng bởi vì tôi đã đọc về IO.readbyte, mà sẽ ném TruncatedDataError. Có vẻ như điều đó KHÔNG áp dụng để đọc. Một chỗ trên một phần của tôi. Cảm ơn! – 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 

Nó hoạt động, mbarkhau. Tôi vừa chuyển định nghĩa hằng số sang lớp File và thêm một vài "self" cho mục đích rõ ràng.

+2

Tôi sẽ không sử dụng MEGABYTE liên tục, thay vào đó: 'def each_chunk (chunk_size = 2 ** 20)' – asaaki

7

Ngoài ra, nếu bạn không muốn monkeypatch File:

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

Ví dụ, streaming một tempfile tải lên một tập tin mới:

# 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

Nếu bạn kiểm tra các tài liệu ruby: http://ruby-doc.org/core-2.2.2/IO.html có một dòng giống như sau:

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

Chỉ báo trước mới có. Kể từ đó, quá trình này có thể đọc các tập tin tạm thời nhanh hơn so với dòng tạo ra, IMO, một độ trễ nên ném trong.

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

Bạn có thể sử dụng IO#each(sep, limit), và thiết lập sep-nil hoặc chuỗi rỗng, ví dụ :

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

Đó chỉ là sai. –

+1

@EricDuminil Cảm ơn bạn đã nhắc nhở tôi, tôi đã quên đối số sep. Nó nên đọc một tập tin trong khối bây giờ. –

Các vấn đề liên quan