使用ruby基于内容拆分大文件

时间:2009-09-21 21:19:44

标签: ruby optimization csv io split

免责声明:我不是程序员,从来没有,从未学过算法,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
}

然后认识到资源效率低下(几个文件打开/关闭)。我确信有更好的方法,你可以解释一下吗?

更新:只是忘了提及,文件在第一列上排序。例如。如果这是hugefile:

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.csvA12345678901.csv的新文件。

2 个答案:

答案 0 :(得分:2)

你的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

答案 1 :(得分:1)

这应该解决多开放写入关闭问题,尽管如果文件数量变大可能会遇到问题;我不能说,我从来没有打开过数百个文件!

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

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 }