Странный Ruby IO с Tempfile

Это сводит меня с ума. Рассмотрим следующее:

require 'open-uri'

#set up tempfile
extname = File.extname file_url
basename = File.basename(file_url, extname)
file = Tempfile.new([basename,extname])

#read form URI into tempfile
uri = URI.parse(file_url)
num_bytes_writen = file.write(uri.read)
puts "Wrote #{num_bytes_writen} bytes"

# Reading from my tempfile
puts "Opening: #{file.path} >>"
puts "#### BEGINING OF FILE ####"
puts  File.open(file.path,'rb').read
puts "#### END OF FILE ####"

Похоже, что байты записываются, но когда я пытаюсь открыть файл, он пуст. Как дела ?!

И, что еще более странно, все работает в консоли Rails, но не при выполнении воркером, запущенным Resque.

Любые идеи? Спасибо, парни


person Jonathan    schedule 13.07.2011    source источник


Ответы (2)


Это проблема буферизации. Вам нужно сбросить буфер ввода-вывода на диск, прежде чем пытаться его прочитать. Либо file.close (если вы закончили с этим), либо file.flush до выполнения File.open для чтения.

Обновлять

Я не думал об этом, но вам не нужно повторно открывать временный файл только для того, чтобы прочитать его. Он уже открыт для записи и чтения, все, что вам нужно сделать, это перейти к началу файла перед чтением. Таким образом, вам не нужно выполнять сброс (потому что вы фактически читаете из буфера)...

# starting partway into your code...
num_bytes_written = file.write(uri.read)
puts "Wrote #{num_bytes_written} bytes"

puts "No need to open #{file.path} >>"
puts "### BEGINNING OF FILE ###"

file.rewind         # set the cursor to the start of the buffer
puts file.read      # cursor is back at the end of the buffer now

puts "### END OF FILE ###"

Еще одно обновление

После комментария от @carp я изменил приведенный выше код, чтобы использовать rewind вместо seek 0, потому что он также сбрасывает lineno на 0 ( и если бы вы этого не сделали, если бы вы использовали lineno, это было бы очень запутанным). Кроме того, на самом деле это более выразительное имя метода.

person smathy    schedule 13.07.2011
comment
file.seek — довольно умный способ сделать это. - person Kasper Grubbe; 13.11.2013
comment
file.seek 0 спас жизнь. Не мог понять, почему мои загруженные файлы были пустыми, но идеальными, если их открывать из папки tmp. - person toxaq; 25.10.2014
comment
Если вы работаете со строковым вводом (например, читаете строку за строкой из текстовых файлов), вы можете использовать file.rewind вместо file.seek 0. - person Carsten; 02.02.2016

Всегда закрывайте файлы. Попробуйте использовать этот стиль в своем коде, чтобы избежать таких ошибок:

File.open(myfile,"w") {|f| f.puts content }

Таким образом, он автоматически вызовет close, когда блок закончится.

person Senthess    schedule 13.07.2011
comment
Это не сработает для Tempfile, потому что ему нужно иметь возможность получить объект ввода-вывода, чтобы он мог открыть файл позже, чтобы прочитать его. - person smathy; 14.07.2011
comment
есть проблема, когда я пишу в цикле, но file.flush очень помогает - person Alexander.Iljushkin; 13.12.2013