Подтвердить что ты не робот

Прочитать файл в кусках в Ruby

Мне нужно прочитать файл в блоках MB, есть ли более чистый способ сделать это в 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
4b9b3361

Ответ 1

Адаптировано из 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

Отказ от ответственности: я новичок в рубине и не тестировал это.

Ответ 2

В качестве альтернативы, если вы не хотите, чтобы monkeypatch File:

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

Например, потоковая передача загруженного tempfile в новый файл:

# 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

Ответ 3

Вы можете использовать IO#each(sep, limit) и установить sep на nil или пустую строку, например:

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

Ответ 4

Если вы просмотрите документы ruby: http://ruby-doc.org/core-2.2.2/IO.html есть строка, которая выглядит следующим образом:

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

Единственное предостережение. Поскольку этот процесс может читать временный файл быстрее, чем генерируемый поток, IMO, нужно залить латентность.

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

Ответ 5

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

Это работает, мбархау. Я просто переместил константное определение в класс File и добавил пару "я" для большей ясности.