如何检测CSV中的最后一行(ruby)

时间:2016-02-24 20:01:42

标签: ruby csv

data = IO::read(file).scrub("")
CSV.parse(data, {:col_sep => "\t", :headers => headers, :quote_char => '_'}) do |row|
  # how to detect last line of CSV?
end

我有一个需要清理的巨型CSV文件。它有多行适用于一个DB对象。在我的代码中,我收集了应用于一个对象的所有行,然后将它们传递给将要处理它们的类。

如果我能够检测到CSV中的最后一行,那么我可以确保最后一个集合被发送。

6 个答案:

答案 0 :(得分:2)

test.csv

first, second, third
1,2,3
3,4,5
7,8,9

test.rb

require 'csv'
headers    = 'headers'
filename   = './test.csv'
line_count = File.readlines(filename).size
file       = File.open(filename, 'r')
data       = IO::read(file).scrub("")
parse_opts = { col_sep: "\t", headers: headers, quote_char: '_'}

CSV.parse(data, parse_opts).to_enum.with_index(1).each do |row, line_num|
  puts line_num == line_count
end
#=> false
#=> false
#=> false
#=> true

在10万行CSV上,line_count在~8秒内生成,您可以使用line_count = %x(wc -l #{filename}).to_i在同一文件上花费约1.7秒。

答案 1 :(得分:1)

File.open(file_path) do |file|
  file.each_line do |line|
    row = CSV.parse_line(line.scrub(""), col_sep: "\t", headers: headers, quote_char: '_')
    file.eof?
  end
end

我使用此解决方案,它不需要在循环之前加载整个CSV文件,这在处理大文件时很有用。

通过使用File.open我可以调用file.eof吗? (文件结束),当我点到最后一行时,它会让我知道。

答案 2 :(得分:1)

这是一个基于搜索的解决方案。这针对较大的文件进行了优化。无论文件的大小如何,打印CSV的最后一行只需要一瞬间:

#!/usr/bin/env ruby

require 'csv'

f = File.open('test.csv')
f.seek(-2, IO::SEEK_END) #pos -1 is newline at end of file
last_line = nil

while f.pos > 0
  if f.getc == "\n"
    last_line = f.read
    break
  else
    f.pos -= 2  #getc advances position by 1
  end
end

row = CSV.parse_line(last_line.scrub(""), col_sep: "\t")
p row

f.close

答案 3 :(得分:0)

试试这个:

f = File.new("testfile")
dummy = f.readlines
f.eof   #=> true

答案 4 :(得分:0)

不是一个非常优雅的解决方案,但也许是这样的?

data = IO::read(file).scrub("")
some_var = IO.readlines(some_file)

CSV.parse(data, {:col_sep => "\t", :headers => headers, :quote_char => '_'}) do |row|
  p row.join == some_var.last.chomp
end

答案 5 :(得分:0)

首先解析数据,你可以像这样检查结果数组的长度。为了使这些代码可以自行运行而不需要重新获取外部csv文件,我将数据放在__END __

之后的__DATA__部分的脚本末尾。
require "csv"

csv = CSV.parse(DATA, :col_sep => ",", :headers => true)
csv.each_with_index do |row, index|
  puts "#{row.fields} #{index+1 == csv.length ? '(last)' : ''}"
end
__END__
nr, Id, Name, URL
1, Google UK, http://google.co.uk
2, Yahoo UK, http://yahoo.co.uk

这给了我们

["1", " Google UK", " http://google.co.uk"] 
["2", " Yahoo UK", " http://yahoo.co.uk"] (last)