Разбиение огромного файла на основе содержимого с помощью ruby - PullRequest
1 голос
/ 22 сентября 2009

Отказ от ответственности: я не программист, никогда не был, никогда не изучал алгоритмы, CS и т. Д. Просто нужно работать с ним.

Мой вопрос: мне нужно разбить огромный (более 4 ГБ) файл 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 ]

2 голосов
/ 22 сентября 2009

Вашему решению 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 голос
/ 22 сентября 2009

Это должно обойти проблему multi-open-write-close, хотя может возникнуть проблема, если количество файлов станет большим; Не могу сказать, у меня никогда не было сотен файлов, открытых для записи!

Важной является первая строка: для каждого нового ключа он открывает новый файл и сохраняет его против этого ключа в хэше. Последняя строка закрывает все открытые файлы.

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 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...