11

非常に大きな CSV ファイルをダウンロードして解凍し、1 行ずつ処理する必要があるという問題があります。ファイルの大きさを教えていただけると助かります。

  • 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私が示したように機能するかどうかはわかりません. ファイルの一部がまだ解凍されていない場合、ファイルの一部を解凍できますか?
  • rubyzip でCSV.foreach動作しInputStreamますか? File行を解析できるように十分に動作しますか? 読みたいのにバッファが空の場合、びっくりしますか?

これが正しいアプローチであるかどうかはわかりません。たぶん、いくつかの EventMachine ソリューションの方が優れているでしょう (ただし、これまで EventMachine を使用したことはありませんが、このようなものでうまく機能する場合は、それで十分です)。

4

1 に答える 1

12

この質問を投稿してからしばらく経ちましたが、他の誰かがそれに出くわした場合に備えて、私が見つけたものを共有する価値があると思いました.

  1. Rubyの標準ライブラリを扱っていた行数CSVが遅すぎました。私のcsvファイルは十分に単純だったので、引用符で囲まれた文字列や型強制を処理するためにすべてのものを必要としませんでした. IO#gets使用するだけで、カンマで行を分割する方がはるかに簡単でした。
  2. httpからcsvデータを含むZip::Inputstreamものまで、すべてをストリーミングできませんでした。IOこれは、zip ファイル構造のエンド オブ セントラル ディレクトリ (EOCD) がファイルの末尾にあるためです。これはファイルを抽出するために必要なため、http からのストリーミングは機能しないようです。

私が最終的に行った解決策は、ファイルをディスクにダウンロードし、Ruby の open3 ライブラリと Linuxunzipパッケージを使用して、圧縮されていない csv ファイルを zip からストリーミングすることでした。

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

-punzipのスイッチは、抽出されたファイルを stdout に送信します。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
于 2015-08-06T13:57:27.677 に答える