奇怪的 Ruby IO 和 Tempfile

12

这让我疯狂。考虑以下内容:

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 Console中一切都正常,但是在由Resque触发的worker执行时却不行。

有什么建议吗?谢谢大家。

2个回答

20
这是一个缓冲问题。 在尝试读取之前,您需要将IO缓冲区刷新到磁盘。 可以使用file.flushfile.close(如果已经完成)在进行读取的File.open之前执行。请注意保留HTML标记。

更新

我没有考虑到这一点,但是您不需要重新打开临时文件才能读取它。 它已经为写入和阅读而打开,您只需要在读取之前将其定位到文件的开头即可。 这样您就不必进行刷新(因为您实际上是从缓冲区读取)... 请注意保留HTML标记。
# 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,没有进行这个操作会非常困惑)。此外,实际上这是一个更具有表现力的方法名。


1
file.seek 是一种相当聪明的做法。 - Kasper Grubbe
1
"file.seek 0" 真是救命稻草。我一直搞不清为什么下载的文件在打开 tmp 文件夹中的文件时完美无缺,但却是空白的。 - toxaq
1
如果您正在处理基于行的输入(例如从文本文件逐行读取),则可能希望使用 file.rewind 而不是 file.seek 0 - Carsten

1

始终关闭您的文件。尝试在您的代码中使用这种风格,以避免此类错误:

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

这样,当代码块结束时,它会自动调用close方法。


这对于“Tempfile”不起作用,因为他需要能够获取IO对象,以便稍后打开文件进行读取。 - smathy
当我循环写入时会出现问题,但是file.flush非常有帮助。 - Alexander.Iljushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接