2

I have a growing file (log) that I need to read by blocks. I make a call by Ajax to get a specified number of lines. I used File.foreach to read the lines I want, but it reads always from the beginning and I need to return only the lines I want, directly.

Example Pseudocode:

 #First call:
  File.open and return 0 to 10 lines

 #Second call:
  File.open and return 11 to 20 lines

 #Third call:
  File.open and return 21 to 30 lines

 #And so on...

Is there anyway to make this?

koxta
  • 846
  • 2
  • 8
  • 30
  • 1
    Take a look here: http://stackoverflow.com/a/5052929/1433751 That should answer your question – Noxx Dec 02 '15 at 10:44

1 Answers1

1

Solution 1: Reading the whole file

The proposed solution here:
https://stackoverflow.com/a/5052929/1433751

..is not an efficient solution in your case, because it requires you to read all the lines from the file for each AJAX request, even if you just need the last 10 lines of the logfile.

That's an enormous waste of time, and in computing terms the solving time (i.e. process the whole logfile in blocks of size N) approaches exponential solving time.

Solution 2: Seeking

Since your AJAX calls request sequential lines we can implement a much more efficient approach by seeking to the correct position before reading, using IO.seek and IO.pos.

This requires you to return some extra data (the last file position) back to the AJAX client at the same time you return the requested lines.

The AJAX request then becomes a function call of this form request_lines(position, line_count), which enables the server to IO.seek(position) before reading the requested count of lines.

Here's the pseudocode for the solution:

Client code:

LINE_COUNT = 10
pos = 0

loop {
  data = server.request_lines(pos, LINE_COUNT)
  display_lines(data.lines)
  pos = data.pos
  break if pos == -1  # Reached end of file
}

Server code:

def request_lines(pos, line_count)
  file = File.open('logfile')

  # Seek to requested position
  file.seek(pos)

  # Read the requested count of lines while checking for EOF
  lines = count.times.map { file.readline if !file.eof? }.compact

  # Mark pos with -1 if we reached EOF during reading
  pos = file.eof? ? -1 : file.pos
  f.close

  # Return data
  data = { lines: lines, pos: pos }
end
Community
  • 1
  • 1
Casper
  • 33,403
  • 4
  • 84
  • 79