2016-02-10 24 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