Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must I .read() a file I wrote before being able to actually output the content to the terminal?

Tags:

ruby

I am learning Ruby and am messing with reading/writing files right now. When I create the file, 'filename', I can write to it with the .write() method. However, I cannot output the content to the terminal without reopening it after running .read() on it (see line 8: puts write_txt.read()). I have tried running line 8 multiple times, but all that does is output more blank lines. Without line 8, puts txt.read() simply outputs a blank line. The following code also works without the puts in line 8 (simply write_txt.read())

# Unpacks first argument to 'filename'
filename = ARGV.first

# Lets write try writing to a file
write_txt = File.new(filename, 'w+')
write_txt.write("OMG I wrote this file!\nHow cool is that?")
# This outputs a blank line THIS IS THE LINE IN QUESTION
puts write_txt.read()

txt = File.open(filename)
# This actually outputs the text that I wrote
puts txt.read()

Why is this necessary? Why is the file that has clearly been written to being read as blank until it is reopened after being read as blank at least once?

like image 863
mattmattmatt Avatar asked Jan 26 '26 08:01

mattmattmatt


1 Answers

When you read or write to a file, there's an internal pointer called a "cursor" that keeps track of where in the file you currently are. When you write a file, the cursor is set to the point after the last byte you wrote, so that if you perform additional writes, they happen after your previous write (rather than on top of it). When you perform a read, you are reading from the current position to the end of the file, which contains...nothing!

You can open a file (cursor position 0), then write the string "Hello" (cursor position 6), and attempting to read from the cursor will cause Ruby to say "Oh hey, there's no more content in this file past cursor position 6", and will simply return a blank string.

You can rewind the file cursor with IO#rewind to reset the cursor to the beginning of the file. You may then read the file (which will read from the cursor to the end of the file) normally.

Note that if you perform any writes after rewinding, you will overwrite your previously-written content.

# Unpacks first argument to 'filename'
filename = ARGV.first

# Lets write try writing to a file
write_txt = File.new(filename, 'w+')
write_txt.write("OMG I wrote this file!\nHow cool is that?")

write_txt.rewind
puts write_txt.read()

Note, however, that it is generally considered bad practice to both read from and write to the same file handle. You would generally open one file handle for reading and one for writing, as mixing the two can have nasty consequenses (such as accidentally overwriting existing content by rewinding the cursor for a read, and then performing a write!)

like image 175
Chris Heald Avatar answered Jan 27 '26 23:01

Chris Heald