1

MySQL テーブルにダンプする 300 を超えるフィールドを含む大きな CSV ファイル (〜 5 GB) の最大フィールド サイズを決定しようとしています。私が持っているファイルの CSV ファイル スキーマでは、最大フィールド長が正しくないため、テーブルのインポートでエラーが発生します。WindowsでRuby 2.0を実行しています。

配列を使用して、フィールドのインデックス (または列) の位置に従って最大フィールド長を格納しています。つまり、ヘッダー内のフィールドの実際の名前は無視しています。ハッシュ、注入、zip などを使用するなど、より手の込んだことを試してみましたが、ここでは単純な配列が最も速く動作するようです。

 field_lengths[0] = Max length of first field   
 field_lengths[1] = Max length of second field
 etc.

ファイルが大きすぎて、一度に丸呑みしたり、CSV を使用して列ごとに解析したりできません。そのため、CSV ファイルを開き、CSV#foreach を使用して各行を解析します (:headers => true オプションを使用してヘッダーを無視します)。行ごとに、フィールド値の解析済み配列をループ処理し、フィールドの長さを field_length 配列に格納されている現在の最大長と比較します。小さなファイルでこれを行うためのはるかに簡単な方法があることに気づきました。この方法は、より大きなファイルに対しては問題なく機能しますが、この方法を使用して特定のファイルの最後まで到達することはできませんでした。

ファイルを終了できないことを回避するために、現在、ヘッダー (=n) を含めて読み取る行数を定義し、n 番目の行に到達したらブレークします。以下の例では、CSV ファイルから 101 行を読み取ります。(ヘッダー行 1 行 + 実際のデータ行 100 行)。プロセスが完了していないため、ファイル内の合計行数はわかりません。

 require 'csv'
 require 'pp'

 data_file = 'big_file.csv'

 # We're only reading the first 101 lines in this example
 n = 101
 field_lengths = []

 File.open(data_file) do |f|
   CSV.foreach(f, :headers => true, :header_converters => :symbol) do |csv_row|
       break if $. > n
       csv_row.fields.each_with_index do |a,i|
           field_lengths[i] ||= a.to_s.length
           field_lengths[i] = a.to_s.length if field_lengths[i] < a.to_s.length
       end
   end
 end

 pp field_lengths

IO#read は特定のバイト数を読み取ることができますが、ファイルをバイト単位で解析すると、レコードが分割される可能性があります。CSV ファイルを小さなファイルに分割して解析するための別の提案はありますか? O'Reilly の Ruby Cookbook (Lucas Carlson & Leonard Richardson、2006 年、第 1 版) では、大きなファイルをチャンクに分割することを提案していますが (以下のように)、この例にそれを拡張する方法、特に改行を扱う方法がわかりません。等

 class File 
    def each_chunk(chunk_size = 1024)
        yield read(chunk_size) until eof?
    end
 end

 open("bigfile.txt") do |f|
    f.each_chunk(15) {|chunk| puts chunk}
 end
4

2 に答える 2

2

CSV.foreach を間違って使用しています。ファイル名に文字列を取ります:

field_lengths = {}

CSV.foreach(data_file, :headers => true, :header_converters => :symbol) do |csv_row|
  csv_row.each do |k, v|
    field_lengths[k] = [field_lengths[k] || 0, v.length].max
  end
end

pp field_lengths
于 2013-07-23T12:21:45.507 に答える