What's going on here? (Newbie question)


#1

In irb:

f = File.new(‘numbers.txt’)
=> #<File:numbers.txt>

f.each {|line| puts line}
123
456
789
=> #<File:numbers.txt>

f.each {|line| puts line}
=> #<File:numbers.txt>

Why doesn’t the second f.each work?


#2

On 6-Jun-06, at 9:36 PM, MB wrote:

f.each {|line| puts line}
=> #<File:numbers.txt>

Why doesn’t the second f.each work?

because as each iterates through the file it “consumes” the file
contents (well, it remembers how far it has got.) You can usually
rewind a file to the beginning, so:

irb(main):001:0> f = File.new(‘numbers.txt’)
=> #<File:numbers.txt>
irb(main):002:0> f.each {|line| puts line}
123
456
789
=> #<File:numbers.txt>
irb(main):003:0> f.pos
=> 12
irb(main):004:0> f.each {|line| puts line}
=> #<File:numbers.txt>
irb(main):005:0> f.pos
=> 12
irb(main):006:0> f.rewind
=> 0
irb(main):007:0> f.each {|line| puts line}
123
456
789
=> #<File:numbers.txt>

Note that some types of file can’t be rewound.

Take a look at what the pos method does, and see if this makes sense.

Hope this helps,

Mike

Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#3

Exactly what I was looking for, thank you.


#4

On Jun 6, 2006, at 9:42 PM, Mike S. wrote:

456
rewind a file to the beginning, so:
irb(main):004:0> f.each {|line| puts line}

Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.

I wonder if IO#each should be changed to automatically #rewind at the
beginning of #each (if possible). I have difficulty imagining a
situation where someone would purposely do
a = file.gets
file.each { … }

But I can certainly imagine people iterating over a file multiple
times. OTOH this may be too magical.


#5

Logan C. wrote:

I wonder if IO#each should be changed to automatically #rewind at the
beginning of #each (if possible). I have difficulty imagining a
situation where someone would purposely do
a = file.gets
file.each { … }

But I can certainly imagine people iterating over a file multiple
times. OTOH this may be too magical.

Too magical. Streams are often one-way. If you need to read the same
data from the same stream more than once, usually the appropriate
method is to store the data in a variable to avoid that. Instead of:

f.each {|s| foo }
f.reset
f.each {|s| bar }

This may often work better:

data = f.read
data.each {|s| foo }
data.each {|s| bar }

Cheers,
Dave


#6

On Jun 6, 2006, at 11:43 PM, Logan C. wrote:

=> #<File:numbers.txt>
456

What about using:

f = IO.readlines(file)

Then the entire file contents will be loaded line-by-line as an
array. You wouldn’t have to worry about rewinding the position in
the actual file.