代码之家  ›  专栏  ›  技术社区  ›  Zsolt Botykai

使用Ruby根据内容拆分大型文件

  •  1
  • Zsolt Botykai  · 技术社区  · 15 年前

    免责声明:我不是一个程序员,从来没有,从来没有学习过算法,CS等。只需要和它一起工作。

    我的问题是:我需要将一个巨大(超过4 GB)的csv文件拆分为较小的文件(然后用 require 'win32ole' )基于第一个字段。在awk中,这相当容易:

    awk -F ',' '{myfile=$1 ; print $0 >> (myfile".csv")}' KNAGYFILE.csv
    

    但与 ruby 我做到了:

    open('hugefile').each { |hline|
        accno = hline[0,12]
        nline = hline[13,10000].gsub(/;/,",")
        accfile = File.open("#{accno.to_s}.csv", "a")
        accfile.puts nline
        accfile.close
    }
    

    然后认识到它的资源效率低下(几个文件打开/关闭)。我肯定有更好的方法,你能解释一下怎么做吗?

    更新: 忘了提一下,文件是按第一列排序的。例如,如果这是巨大的:

    012345678901,1,1,1,1,1,1
    012345678901,1,2,1,1,1,1
    012345678901,1,1,A,1,1,1
    012345678901,1,1,1,1,A,A
    A12345678901,1,1,1,1,1,1
    A12345678901,1,1,1,1,1,1
    A12345678901,1,1,1,1,1,1
    A12345678901,1,1,1,1,1,1
    

    然后我需要两个新文件,名为 012345678901.csv A12345678901.csv .

    2 回复  |  直到 15 年前
        1
  •  2
  •   glenn jackman    15 年前

    您的awk解决方案将不得不多次打开该文件,因此我认为您将获得相同的资源使用率。

    您可以将文件保持打开状态,直到$1发生更改:

    prev = nil
    File.foreach('hugefile') do |hline|
      accno = hline[0,12]
      nline = hline[13,10000].gsub(/;/,",")
      if prev != accno
        accfile.close rescue nil
        accfile = File.open("#{accno.to_s}.csv", "a")
        prev = accno
      end
      accfile.puts nline
    end
    
        2
  •  1
  •   Mike Woodhouse    15 年前

    这应该解决多打开写关闭的问题,尽管如果文件数量变大可能会遇到问题;我不能说,我从未打开过数百个文件进行写操作!

    第一行是重要的一行:对于遇到的每个新密钥,它都会打开一个新文件,并将其与该密钥存储在哈希中。最后一行关闭所有打开的文件。

    files = Hash.new { |h, k| h[k] = File.open("#{k}.csv", 'w+') }
    open('hugefile').each do |hline|
      files[hline[0,12]].puts hline[13,10000].gsub(/;/,",")
    end
    files.each { |n, f| f.close }