2014-04-29 45 views
6

我有問題需要下載,解壓縮,然後逐行處理一個非常大的CSV文件。我認爲這是有益的給你一個想法的文件有多大:用ruby流解壓大csv文件

  • big_file.zip〜700MB
  • big_file.csv〜23GB

這裏的一些事情,我想發生:

  • 不必下載整個文件解壓
  • 之前,不要有分析CSV行之前解壓整個文件
  • 在做所有這些時不要用盡太多內存/磁盤

我不知道這是否可行。這是我的想法是:

require 'open-uri' 
require 'rubyzip' 
require 'csv' 

open('http://foo.bar/big_file.zip') do |zipped| 
    Zip::InputStream.open(zipped) do |unzipped| 
    sleep 10 until entry = unzipped.get_next_entry && entry.name == 'big_file.csv' 
    CSV.foreach(unzipped) do |row| 
     # process the row, maybe write out to STDOUT or some file 
    end 
    end 
end 

這是我知道的問題:

  • open-uri讀取整個響應,並將其保存到一個Tempfile這是沒有好這個大小的文件。我可能需要直接使用Net::HTTP,但我不知道如何做到這一點,仍然可以獲得IO
  • 我不知道下載速度有多快,或者Zip::InputStream的工作方式如何,我已經證明它的工作原理。當它還沒有完成時,它可以解壓縮一些文件嗎?
  • CSV.foreach可以使用rubyzip的InputStream嗎?它的行爲足夠像File它能夠解析出行嗎?如果它想讀取但是緩衝區是空的,它會嚇壞了嗎?

我不知道這是否是正確的方法。也許一些EventMachine解決方案會更好(雖然我以前從未使用EventMachine,但如果它對這樣的事情更好,我完全贊成)。

+0

我不認爲流式傳輸的zip會正常工作,因爲zip文件的結構如何。如果zip中只有一個文件(或者我想要的文件是第一個文件),那麼它可能會做一些類似'funzip'的事情,但事實並非如此。 – ZombieDev

回答

6

我發佈這個問題已經有一段時間了,如果有其他人遇到它,我認爲它可能是值得分享我發現的。

  1. 對於我正在處理Ruby的標準庫CSV的行數太慢了。我的csv文件很簡單,我不需要所有的東西來處理引用的字符串或強制類型強制。只要使用IO#gets然後再用逗號分隔線就容易多了。
  2. 我無法將包含csv數據的一些內容從http流式傳輸到Zip::Inputstream到某些IO。這是因爲zip file structure在文件末尾有中央目錄結束(EOCD)。這是需要爲了提取文件,使它從http流看起來似乎不會工作。

我最終選擇的解決方案是將文件下載到磁盤,然後使用Ruby的open3庫和Linux unzip包從zip壓縮未壓縮的csv文件。

require 'open3' 

IO.popen('unzip -p /path/to/big_file.zip big_file.csv', 'rb') do |io| 
    line = io.gets 
    # do stuff to process the CSV line 
end 

-p開啓解壓縮將提取的文件發送到標準輸出。 IO.popen然後用管道製作一個紅寶石的IO對象。工作很好。如果您需要額外的處理,您也可以將它與CSV一起使用,但對我來說這太慢了。

require 'open3' 
require 'csv' 

IO.popen('unzip -p /path/to/big_file.zip big_file.csv', 'rb') do |io| 
    CSV.foreach(io) do |row| 
    # process the row 
    end 
end