Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird Ruby IO with Tempfile

This is driving me crazy. Consider the following:

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 ####"

It looks like bytes get written, but when I try to open the file -- its empty. Whats up ?!

And to make it more weird -- everyting works in the Rails Console, but not when executed by a worker triggered by Resque.

Any ideas? Thanks guys

like image 393
Jonathan Avatar asked Jul 13 '11 21:07

Jonathan


People also ask

What is Tempfile Ruby?

A utility class for managing temporary files. When you create a Tempfile object, it will create a temporary file with a unique filename. A Tempfile objects behaves just like a File object, and you can perform all the usual file operations on it: reading data, writing data, changing its permissions, etc.


2 Answers

This is a problem of buffering. You need to flush the IO buffer to disk before trying to read it. Either file.close (if you've finished with it) or file.flush before doing the File.open for the read.

Update

I hadn't thought about this, but you don't need to reopen the temp file just to read it. It's already open for writing and reading, all you need to do is seek to the start of the file before reading. This way you don't have to do the flush (because you're actually reading from the buffer)...

# 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 ###"

Another Update

After a comment from @carp I have adjusted the code above to use rewind instead of seek 0 because it also resets lineno to 0 (and not having that done, if you were using lineno would be very confusing). Also actually it's a more expressive method name.

like image 89
smathy Avatar answered Nov 07 '22 21:11

smathy


Always close your files. Try using this style in your code, to avoid such mistakes:

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

This way, it will automatically call close when the block ends.

like image 20
Senthess Avatar answered Nov 07 '22 22:11

Senthess