4

つまり、行の長さが異なる20,000,000行のcsvファイルがあります。これは、古風なデータロガーと独自のフォーマットによるものです。最終結果は、次の形式のcsvファイルとして取得されます。私の目標は、このファイルをpostgresデータベースに挿入することです。どうすれば次のことができますか?

  • 一貫性のあるCSVファイルを作成するために、最初の8列と最後の2列を保持します
  • csvファイルの最初または最後の位置に新しい列を追加します。

1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0, img_id.jpg, -50
1, 2, 3, 4, 5, 0,0,0,0,0,0,0,0,0,0,0 img_id.jpg, -50
4

4 に答える 4

8

で行を読み取りcsv、次に:

newrow = row[:8] + row[-2:]

次に、新しいフィールドを追加して書き出します(これもcsv)。

于 2010-03-31T01:00:55.740 に答える
2

ファイルをテキストファイルとして開き、一度に1行ずつ読み取ることができます。「フィールドを分割」しない引用符またはエスケープされたコンマはありますか?そうでない場合は、

with open('thebigfile.csv', 'r') as thecsv:
    for line in thecsv:
        fields = [f.strip() for f in thecsv.split(',')]
        consist = fields[:8] + fields[-2:] + ['onemore']
        ... use the `consist` list as warranted ...

あなたが言うように、私が持っている場所では+ ['onemore']、いくつかの非常に異なる内容で「列を追加」したいと思うかもしれませんが、もちろんそれが何であるかは推測できません。

DBへの挿入とともに各行を個別に送信しないでください。2,000万回の挿入には長い時間がかかります。むしろ、「一貫性のある」リストをグループ化し、一時リストに追加します。リストの長さがたとえば1000に達するたびに、を使用しexecutemanyてこれらすべてのエントリを追加します。

編集:明確にするために、 「適切な」csv形式ではないことがわかっているファイルの処理に使用することはお勧めしません。ファイルを直接処理すると、より直接的な制御が可能になります(特に、カンマの数が変化する以外の不規則性を発見した場合)。ライン)。csv

于 2010-03-31T01:06:35.150 に答える
1

モジュールの使用をお勧めしcsvます。これが私が他の場所で行ったCSV処理に基づくいくつかのコードです

from __future__ import with_statement
import csv

def process( reader, writer):
    for line in reader:
        data = row[:8] + row[-2:]
        writer.write( data )

def main( infilename, outfilename ):
    with open( infilename, 'rU' ) as infile:
        reader = csv.reader( infile )
        with open( outfilename, 'w') as outfile:
            writer = csv.writer( outfile )
            process( reader, writer )

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print "syntax: python process.py filename outname"
        sys.exit(1)
    main( sys.argv[1], sys.argv[2] )
于 2010-03-31T01:19:55.150 に答える
1

申し訳ありませんが、これを使用してコードを作成する必要があります。このような巨大なファイルがある場合は、すべてをチェックして、期待するものと一致していることを確認する価値があります。不幸なデータをデータベースに入れてしまうと、すべてを取り出すことはできません。

CSVの奇妙な点を覚えておいてください。これは、引用符、エスケープ、ヌル文字、Unicode、空のフィールド( ",,,")、複数行の入力、および空白行に関するさまざまなルールを持つ、多数の同様の標準のミッシュマッシュです。csvモジュールには「方言」とオプションがあり、csv.Snifferクラスが役立つ場合があります。

私はあなたをお勧めします:

  • 'tail'コマンドを実行して、最後の数行を確認します。
  • 正常に動作しているように見える場合は、ファイル全体をcsvリーダーで実行して、ファイルが壊れていることを確認します。「1行あたりのフィールド数」の簡単なヒストグラムを作成します。
  • 「有効な」範囲と文字タイプについて考え、読みながらそれらを厳密にチェックしてください。特に、印刷可能な範囲外の異常なUnicodeまたは文字に注意してください。
  • 「残りの行」のテキストフィールドに余分な奇数ボールの値を保持するかどうかを真剣に検討してください。
  • 予期しない行を例外ファイルに入れます。
  • 例外ファイルの新しいパターンを処理するようにコードを修正します。リンス。繰り返す。
  • 最後に、すべてを再度実行して、実際にデータをデータベースにダンプします。

データベースに触れないことから完全に完了するまで、開発時間は速くなります。また、SQLiteは読み取り専用データで非常に高速であるため、PostGresが最善のソリューションではない可能性があることに注意してください。

最終的なコードはおそらく次のようになりますが、データ、特に「正常に動作する」データを知らなければ、確信が持てません。

while not eof
    out = []
    for chunk in range(1000):
       try:
          fields = csv.reader.next()
       except StopIteration:
          break
       except:
          print str(reader.line_num) + ", 'failed to parse'"
       try:
          assert len(fields) > 5 and len(fields < 12)
          assert int(fields[3]) > 0 and int(fields[3]) < 999999
          assert int(fields[4]) >= 1 and int(fields[4] <= 12) # date
          assert field[5] == field[5].strip()  # no extra whitespace
          assert not field[5].strip(printable_chars)  # no odd chars
          ...
       except AssertionError:
          print str(reader.line_num) + ", 'failed checks'"
       new_rec = [reader.line_num]  # new first item
       new_rec.extend(fields[:8])   # first eight
       new_rec.extend(fields[-2:])  # last two
       new_rec.append(",".join(field[8:-2])) # and the rest
       out.append(new_rec)
    if database:
       cursor.execute_many("INSERT INTO raw_table VALUES %d,...", out)

もちろん、あなたのマイレージはこのコードによって異なります。これは、pseduoコードの最初のドラフトです。入力用の堅実なコードを書くのに1日かかることを期待してください。

于 2010-03-31T09:02:12.137 に答える