tags:

views:

202

answers:

4

How to read the prevous line of a file. The opposite of IO.gets.I initially thought to set IO.lineno to the line number I wanted to read but that doesn't work as expect. How do you actually read the previous line?

+2  A: 

There are a couple of ways, it depends on how much information you have at your disposal. If you know the length of the last line you read in you can take the easiest approach which would be

# assume f is the File object
len = last_line_length
f.seek -len, IO::SEEK_CUR

Of course, if you are not provided that information things become a little less nice. You could use the same approach as above to walk backwards (one byte at a time) until you hit a newline marker or take lineno and read from the beginning. Something like

lines = f.lineno
f.rewind
(lines - 1).times { f.gets }

However, as far as I know, there is no direct mechanism to just go back 1 N where N represents a line.

As an aside, you should know that while you can write to File.lineno doing so does not actually affect the position in the file and it also ruins the accuracy of the variable for reads after that point.

ezpz
+4  A: 

One simple way is to remember the previous line you read:

prev = nil
File.foreach('_vimrc') do |line|
  p [line, prev]  # do whatever processing here
  prev = line
end
glenn jackman
A: 

Saw an excellent suggestion on comp.lang.ruby -- use IO.tell to keep track of the position of each line in the file so you can seek directly to it:

File.open "foo" do |io|
  idx = [io.tell]
  while l = io.gets
    p l
    idx << io.tell
  end
end
glenn jackman
+1  A: 

The Elif gem has a gets method that is the opposite of IO.gets.

$ sudo gem install elif

$ irb

require "elif"
last_syslog = Elif.open('/var/log/syslog') { |file| file.gets }
Jonas Elfström