2016-02-10 43 views
2

我打開一個csv文件,使用追加方法'a'來編寫一個新行,作爲每次調用函數的結果,使用DictWriter(僅寫入一個新的來自每個呼叫的行)。使用'a'方法寫入csv:標題和新值

keys = ['15000', '15001', '15002', '15003']

values = [18, 20, 3, 9] ##changes each time function run

值的變化我每次樂趣的功能。鍵通常保持不變,但是隨着我從XML文件中刪除更多,將來可能會添加更多(關聯新值)。因此,我希望能夠一致地將值映射到字段名稱。

with open('myfile.csv', 'a') as csvfile: 
    w = csv.DictWriter(csvfile, fieldnames = keys, lineterminator='\n') 
    w.writerheader() 
    w.writerow(dict(zip(fnames, values))) 

這裏的問題是,每次writerheader()都將標題寫入前一行。由此產生的csv看起來像:

15000, 15001, 15002, 15003 
18, 20, 3, 9 
15000, 15001, 15002, 15003 
20, 15, 4, 12 

我想這不會有重複的標題。我知道我可以用一個csv作爲頭文件,只有最初的鍵,但是這並不能解決我的問題,如果字典鍵在將來的函數調用中改變。另外,如果添加了新的鍵,這將持續地將值映射到鍵?我會遇到問題嗎?

P.S.請注意,我添加了lineterminated = '\n'段作爲默認DictWriter方法正在每個追加創建一個空行。

+0

你想在這裏得到什麼輸出?通常,您將使用csv模塊讀取或寫入整個文件,而不是追加到現有文件。 –

+0

'writeheader()'函數將會寫入頭文件,這就是目的,所以這裏不要感到意外。您可以嘗試僅在空文件中調用它,這可能會解決標題問題。但是,向現有的CSV文件添加列並不是您想要做的事情。爲什麼不使用SQLite來累積數據,然後將其導出到CSV? – Maciek

+0

謝謝,我會研究一下。我知道追加當前文件不是典型的方法,但總是準備嘗試失敗!儘管writeheader()可以重寫現有csv文件的第一行。 – jmk

回答

1

聽起來好像你需要在列更改時重寫整個CSV文件。

如果新列被附加到現有的鍵上,當前數據行將需要添加一個空字段。或者,您可能需要添加一些默認值,而不是空白字段。

因此,您需要使用DictReader打開現有的CSV文件。獲取fieldnames並追加新的列。然後從原始文件中讀取每一行,可選擇使用新列的默認值更新字典。然後將其寫入一個新文件,其中DictWriter配置了新的fieldnames。最後添加你的新行。

import os 
import shutil 
from csv import DictReader, DictWriter 
from tempfile import NamedTemporaryFile 

def append_csv(csv_filename, data): 
    with open(csv_filename, 'a+') as csv_file: 
     reader = DictReader(csv_file) 
     new_keys = set(data.keys()).difference(reader.fieldnames) 
     if not new_keys: 
      csv_file.seek(0, os.SEEK_END) 
      writer = DictWriter(csv_file, reader.fieldnames) 
      writer.writerow(data) 
     else: 
      reader.fieldnames.extend(sorted(new_keys)) 
      with NamedTemporaryFile(dir='.', delete=False) as csv_tmpfile: 
       writer = DictWriter(csv_tmpfile, reader.fieldnames, lineterminator='\n') 
       writer.writeheader() 
       writer.writerows(row for row in reader) 
       writer.writerow(data) 
      shutil.move(csv_tmpfile.name, csv_filename) 

如果字段經常變化,這將是非常低效的。相反,您可能想要在列更改時寫入單獨的CSV文件,然後稍後再執行合併。

+0

謝謝,在這種情況下,看起來可能有點多,但謝謝你的建議。由於標題不經常改變,我可能依靠手動方法 – jmk