Skizit
Skizit

Reputation: 44862

How to get a particular line from a file

Is it possible to extract a particular line from a file knowing its line number? For example, just get the contents of line N as a string from file "text.txt"?

Upvotes: 24

Views: 25715

Answers (7)

anothermh
anothermh

Reputation: 10564

These solutions work if you want only one line from a file, or if you want multiple lines from a file small enough to be read repeatedly. Large files (for example, 10 million lines) take much longer to search for a specific line so it's better to get the necessary lines sequentially in a single read so the large file doesn't get read multiple times.

Create a large file:

File.open('foo', 'a') { |f| f.write((0..10_000_000).to_a.join("\n")) }

Pick which lines will be read from it and make sure they're sorted:

lines = [9_999_999, 3_333_333, 6_666_666].sort

Print out those lines:

File.open('foo') do |f|
  lines.each_with_index do |line, index|
    (line - (index.zero? ? 0 : lines[index - 1]) - 1).times { f.gets }
    puts f.gets
  end
end

This solution works for any number of lines, does not load the entire file into memory, reads as few lines as possible, and only reads the file one time.

Upvotes: 0

steenslag
steenslag

Reputation: 80085

File has a nice lineno method.

def get_line(filename, lineno)
  File.open(filename,'r') do |f|
     f.gets until f.lineno == lineno - 1
     f.gets
  end
end

Upvotes: 4

Nakilon
Nakilon

Reputation: 35102

Try one of these two solutions:

file = File.open "file.txt"

#1 solution would eat a lot of RAM
p [*file][n-1]

#2 solution would not
n.times{ file.gets }
p $_

file.close

Upvotes: 16

Maxim Kulkin
Maxim Kulkin

Reputation: 2788

If you want one liner and do not care about memory usage, use (assuming lines are numbered from 1)

lineN = IO.readlines('text.txt')[n-1]

or

lineN = f.readlines[n-1]

if you already have file opened.

Otherwise it would be better to do like this:

lineN = File.open('text.txt') do |f|
          (n-1).times { f.gets } # skip lines preceeding line N
          f.gets                 # read line N contents
        end

Upvotes: 0

ghostdog74
ghostdog74

Reputation: 343087

linenumber=5
open("file").each_with_index{|line,ind|
  if  ind+1==linenumber
    save=line
    # break or exit if needed.
  end
}

or

linenumber=5
f=open("file")
while line=f.gets
  if $. == linenumber # $. is line number
    print "#{f.lineno} #{line}" # another way
    # break  # break or exit if needed
  end
end
f.close

If you just want to get the line and do nothing else, you can use this one liner

ruby -ne '(print $_ and exit) if $.==5' file

Upvotes: 2

August Lilleaas
August Lilleaas

Reputation: 54603

def get_line_from_file(path, line)
  result = nil

  File.open(path, "r") do |f|
    while line > 0
      line -= 1
      result = f.gets
    end
  end

  return result
end

get_line_from_file("/tmp/foo.txt", 20)

This is a good solution because:

  • You don't use File.read, thus you don't read the entire file into memory. Doing so could become a problem if the file is 20MB large and you read often enough so GC doesn't keep up.
  • You only read from the file until the line you want. If your file has 1000 lines, getting line 20 will only read the 20 first lines into Ruby.

You can replace gets with readline if you want to raise an error (EOFError) instead of returning nil when passing an out-of-bounds line.

Upvotes: 6

Jonas Elfström
Jonas Elfström

Reputation: 31458

You could get it by index from readlines.

line = IO.readlines("file.txt")[42]

Only use this if it's a small file.

Upvotes: 27

Related Questions