Skipping the first line when reading in a file in 1.9.3
Asked Answered
N

8

17

I'm using ruby's File to open and read in a text file inside of a rake task. Is there a setting where I can specify that I want the first line of the file skipped? Here's my code so far:

desc "Import users." 
  task :import_users => :environment do 
    File.open("users.txt", "r", '\r').each do |line| 
      id, name, age, email = line.strip.split(',') 
      u = User.new(:id => id, :name => name, :age => age, :email => email) 
      u.save 
    end 
  end

I tried line.lineno and also doing File.open("users.txt", "r", '\r').each do |line, index| and next if index == 0 but have not had any luck.

Nock answered 8/3, 2012 at 8:4 Comment(0)
B
22

Change each to each_with_index do |line, index| and next if index == 0 will work.

Brent answered 8/3, 2012 at 8:16 Comment(0)
P
24

function drop(n) will remove n lines from the beginning:

File.readlines(filename).drop(1).each do |line| 
  puts line
end 

It will read the whole file into an array and remove first n lines. If you are reading whole file anyway it's probably the most elegant solution.

When reading larger files foreach will be more efficient, as it doesn't read all data into memory:

File.foreach(filename).with_index do |line, line_num|
  next if line_num == 0
  puts line
end
Presume answered 4/2, 2013 at 14:10 Comment(1)
you mean File.readlines("users.txt").drop(1).each do |line| , your example gives an errorPorpoise
B
22

Change each to each_with_index do |line, index| and next if index == 0 will work.

Brent answered 8/3, 2012 at 8:16 Comment(0)
S
9
File.open("users.txt", "r", '\r') do |file|
  lines = file.lines # an enumerator
  lines.next #skips first line
  lines.each do |line|
    puts line # do work
  end
end

Making use of an enumerator, which 'remembers' where it is.

Sension answered 8/3, 2012 at 8:21 Comment(0)
A
4

You probably really want to use csv:

CSV.foreach("users.txt", :headers, :header_converters => :symbol, :col_sep => ',') do |row|
  User.new(row).save
end 
Ancier answered 8/3, 2012 at 8:49 Comment(0)
B
4
File.readlines('users.txt')[1..-1].join()

Works good too.

Bellamy answered 27/12, 2012 at 19:42 Comment(1)
File.readlines('users.txt').drop(1).join is even a little bit simpler :)Flea
I
2

if you want to keep the file as IO the whole time (no array conversions) and you plan on using the data in the first line:

f = File.open('users.txt', 'r')
first_line = f.gets
body = f.readlines

More likely though, what you want is handled by CSV or FasterCSV as others have pointed out. My favorite way to handle files with a header line is to do:

FasterCSV.table('users.txt')
Inimitable answered 1/5, 2013 at 23:16 Comment(0)
P
1

Since a few answers (no longer ?) work in Ruby 1.9.3, here a working sample of the three best methods

# this line must be dropped
puts "using drop"
File.readlines(__FILE__).drop(1).each do |line| 
  puts line
end 
puts ""

puts "using a range"
File.readlines(__FILE__)[1..-1].each do |line| 
  puts line
end
puts ""

puts "using enumerator"
File.readlines(__FILE__).each do |file, w|
    lines = file.lines # an enumerator
    lines.next #skips first line
    lines.each do |line|
        puts line
    end
end
Porpoise answered 29/10, 2014 at 16:48 Comment(0)
T
0

The OP said lineno didn't work for them, but I'm guessing it wasn't applied in the correct way. There's lots of ways achieve what the OP is asking for, but using lineno might help you shorten up your code without having to use readlines, which is sometimes too memory intensive.

From the 1.9.3 docs

f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }

produces:

1: This is line one
2: This is line two
3: This is line three
4: And so on...

Note that is a method you can call from the file object, but not the object yielded to the block.

   2:     require 'pry'; binding.pry
=> 3:   f.each {|line| puts line.lineno }

[1] pry(#<SomeFile>)> line.lineno
NoMethodError: undefined method `lineno' for #<String:0x00007fa7d682b920>

You can find the same example with identical code in docs for the latest stable version of Ruby today (2.5.1).

So going off the example, the code might look like

f = File.new("testfile")
o = File.open("output.txt", w)
f.each do |line|
  next if f.lineno == 1
  o << line
end
Tia answered 17/8, 2018 at 0:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.