2010-03-31 115 views
2

總之,我有一個20,000,000行的csv文件,它具有不同的行長度。這是由於古老的數據記錄器和專有格式。我們以如下格式獲得最終結果作爲csv文件。我的目標是將這個文件插入到postgres數據庫中。我怎麼能做到以下幾點:Python - CSV:具有不同長度行的大文件

  • 保持第一8列和我的最後2列,有一個一致的CSV文件
  • 在第一個或最後一個位置,以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 
+0

您可以指定「將列添加到文件中」的含義嗎?本專欄的數據來自哪裏? – 2010-03-31 01:01:02

+0

這將幫助我們瞭解您遇到問題的步驟。你不知道如何將行分隔成列嗎?你不知道如何跳過某些列嗎?如果您只是不知道如何開始,請繼續並指定,並且有人也可以回答。 – Wesley 2010-03-31 01:04:35

+0

@Mark Byers,添加列可以在開始或結束。 @韋斯利,我堅持的部分是如何跳過某些列;然而,我認爲Ignacio可能已經回答了下面的問題 – dassouki 2010-03-31 01:06:29

回答

7

閱讀一排csv,則:

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

然後添加新的領域,它(與csv也)寫出來的。

2

您可以將文件作爲文本文件打開並逐行讀取一行。有沒有引用或逃避不會「拆分字段」的逗號?如果沒有,你可以做

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年 - 2000個萬元刀片將採取時間。而是將「生成一致的」列表分組,並將它們附加到一個臨時列表中 - 每次列表的長度達到1000時,使用executemany來添加所有這些條目。

編輯:爲了澄清,我建議使用csv處理您知道一個文件是不是「適當」的CSV格式:處理直接給你更多的直接控制(尤其是當你會發現每行不同數量的逗號之外的其他違規行爲)。

+0

在這個答案中有很多偉大的建議。我不知道爲什麼有一個downvote。 + 1ed – YOU 2010-03-31 01:27:33

+0

嗯..似乎有問題,用逗號引用的行會導致錯誤。 – 2010-03-31 08:12:22

+0

@Charles,當然,這就是爲什麼我說「如果沒有,......」;-)。如果您需要更復雜的「語法」來解析「不完美的csv」並提取字段,則可以根據需要逐步應用解析優化(csv模塊,雖然適用於處理_good_ csv文件,但卻不能傳入數據中不完善的解決方案的廣度)。 – 2010-03-31 14:19:21

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]) 
+0

出於好奇,你爲什麼使用而不是? – dassouki 2010-03-31 01:22:14

+1

@dassouki:'for'在'process()'中。 – 2010-03-31 01:24:44

1

對不起,您需要編寫一些代碼,這一個。當你有這樣一個巨大的文件時,值得檢查一下,以確保它符合你的期望。如果你讓不愉快的數據進入你的數據庫,你永遠不會把它全部拿出來。

記住一些關於CSV的怪異特性:它是一組類似標準的混雜體,它們有關引用,轉義,空字符,unicode,空字段(「,,,」), 多行輸入和空行。 csv模塊有'方言'和選項,你可能會發現csv.Sniffer類很有幫助。

我建議你:

  • 運行一個「尾巴」的命令來看看最後幾行。
  • 如果表現良好,請通過csv閱讀器運行整個文件,以查看 它是否中斷。快速製作「每行場數」直方圖。
  • 想想「有效」範圍和字符類型,並嚴格檢查它們爲 您閱讀。尤其要注意可打印範圍以外的不尋常的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-code的初稿。預計編寫可靠代碼的輸入需要大部分時間。

相關問題