From: Jesús Gabriel y Galán on
On Thu, Jul 22, 2010 at 8:35 AM, Robert Klemme
<shortcutter(a)googlemail.com> wrote:
> On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:
>>
>> (2010/07/22 14:08), Urabe Shyouhei wrote:
>>>
>>> Take a look at the doc for File.readline.
>>
>> Oops... typo.  I meant readlines.  With it you can do something like
>> File.readlines(f).last
>
> This is as inefficient as using File.foreach because it will read the whole
> file.  I believe Ted was looking for a more efficient solution.
>
> Ted, if you want to do this in Ruby and not resort to tail you can use
> IO#seek to seek to the end of the file and read backwards until you have
> read more than one line.

I think this is the algorithm used by James Gray in Elif:

http://elif.rubyforge.org/

From those docs:

" gets(sep_string = $/)

The second half on the Elif algorthim (see Elif::new). This method
returns the next line of the File, working from the end to the
beginning in reverse line order.

It works by moving the file pointer backwords MAX_READ_SIZE at a time,
storing seen lines in @line_buffer. Once the buffer contains at least
two lines (ensuring we have seen on full line) or the file pointer
reaches the head of the File, the last line from the buffer is
returned. When the buffer is exhausted, this will throw nil (from the
empty Array)."


Jesus.

From: Urabe Shyouhei on
(2010/07/22 15:35), Robert Klemme wrote:
> On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:
>> (2010/07/22 14:08), Urabe Shyouhei wrote:
>>> Take a look at the doc for File.readline.
>>
>> Oops... typo. I meant readlines. With it you can do something like
>> File.readlines(f).last
>
> This is as inefficient as using File.foreach because it will read the
> whole file. I believe Ted was looking for a more efficient solution.

Then how about:

File.open(f).each_line.inject(nil){|x,y|y}

Slower than my first answer though.

From: Robert Klemme on
2010/7/22 Urabe Shyouhei <shyouhei(a)ruby-lang.org>:
> (2010/07/22 15:35), Robert Klemme wrote:
>> On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:
>>> (2010/07/22 14:08), Urabe Shyouhei wrote:
>>>> Take a look at the doc for File.readline.
>>>
>>> Oops... typo.  I meant readlines.  With it you can do something like
>>> File.readlines(f).last
>>
>> This is as inefficient as using File.foreach because it will read the
>> whole file.  I believe Ted was looking for a more efficient solution.
>
> Then how about:
>
> File.open(f).each_line.inject(nil){|x,y|y}
>
> Slower than my first answer though.

This still reads in the whole file plus you do not close the File
object properly. A solution that is efficient for large files will
use File#seek to move position to the end of the file and go backwards
from there.

Cheers

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

From: Ted Flethuseo on
Robert Klemme wrote:
> On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:
>> (2010/07/22 14:08), Urabe Shyouhei wrote:
>>> Take a look at the doc for File.readline.
>>
>> Oops... typo. I meant readlines. With it you can do something like
>> File.readlines(f).last
>
> This is as inefficient as using File.foreach because it will read the
> whole file. I believe Ted was looking for a more efficient solution.
>
> Ted, if you want to do this in Ruby and not resort to tail you can use
> IO#seek to seek to the end of the file and read backwards until you have
> read more than one line.
>
> Kind regards
>
> robert

Interesting, the problem is how to find how far back I need to go in the
seek (automatically of course)

f = File.new("testfile")
f.seek(-13, IO::SEEK_END) #=> 0
f.readline #=> "And so on...\n"

Ted.
--
Posted via http://www.ruby-forum.com/.

From: Urabe Shyouhei on
(2010/07/22 22:06), Robert Klemme wrote:
>> Then how about:
>>
>> File.open(f).each_line.inject(nil){|x,y|y}
>>
>> Slower than my first answer though.
>
> This still reads in the whole file plus you do not close the File
> object properly.

I'm sure you know how to do that properly.

> A solution that is efficient for large files will
> use File#seek to move position to the end of the file and go backwards
> from there.

No, that can't work -- or that works only when you are sticking on the ASCII
character set. Multibyte encodings are not safe to read backwards
(sometimes). The only safe way is to read the whole content from the
beginning, at least one time.