【问题标题】:How to detect the last row in CSV (ruby)如何检测CSV(红宝石)中的最后一行
【发布时间】:2016-02-24 20:01:41
【问题描述】:
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 中的最后一行,那将非常有帮助,这样我就可以确保发送最后一个集合。

【问题讨论】:

    标签: ruby csv


    【解决方案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
    

    【讨论】:

      【解决方案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
      

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

      【讨论】:

        【解决方案3】:

        通过首先解析数据,您可以像这样检查结果数组的长度。为了使此代码可以自行运行而无需重新获取外部 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)
        

        【讨论】:

          【解决方案4】:
          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? (文件结尾)这让我知道我什么时候打到最后一行。

          【讨论】:

          • 内部块不会一直运行直到它用完行,因此当该块结束时您将位于文件的末尾?
          • 正确。当它到达最后一行并想在 each_line 块中触发它时,我试图触发它。
          【解决方案5】:

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

          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
          

          【讨论】:

            【解决方案6】:

            试试这个:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-02-28
              • 1970-01-01
              • 1970-01-01
              • 2014-02-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多