Question

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.

Was it helpful?

Solution

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

OTHER TIPS

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

File.readlines('users.txt').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.

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.

You probably really want to use csv:

CSV.foreach("users.txt", :headers, :header_converters => :symbol, :col_sep => ',') do |row|
  User.new(row).save
end 
File.readlines('users.txt')[1..-1].join()

Works good too.

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')

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

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top