Python CSV,仅写入一次标题

41

我有一个程序,可以将 .Json 文件转换为 CSV。

首先,我会加载这个 json 文件。

f = open('Data.json')
data = json.load(f)
f.close()

然后我会仔细查找其中的特定关键字,如果我找到了这个关键字,我会将所有相关内容写入一个 .csv 文件。

for item in data:
    if "light" in item:
       write_light_csv('light.csv', item)

这是我的write_light_csv函数:

def write_light_csv(filename,dic):

    with open (filename,'a') as csvfile:
        headers = ['TimeStamp', 'light','Proximity']
        writer = csv.DictWriter(csvfile, delimiter=',', lineterminator='\n',fieldnames=headers)

        writer.writeheader()

        writer.writerow({'TimeStamp': dic['ts'], 'light' : dic['light'],'Proximity' : dic['prox']})

我最初选择了wb+作为模式,但每次打开文件进行写操作时都会清除所有内容。我将其替换为a,现在每次写入时它会添加一个标题。如何确保标题只被写入一次?

8个回答

69

您可以检查文件是否已经存在,如果是,则不调用writeheader()函数,因为您正在使用追加选项打开文件。

类似这样:

import os.path


file_exists = os.path.isfile(filename)

with open (filename, 'a') as csvfile:
    headers = ['TimeStamp', 'light', 'Proximity']
    writer = csv.DictWriter(csvfile, delimiter=',', lineterminator='\n',fieldnames=headers)

    if not file_exists:
        writer.writeheader()  # file doesn't exist yet, write a header

    writer.writerow({'TimeStamp': dic['ts'], 'light': dic['light'], 'Proximity': dic['prox']})

@Kos 如果在with块中没有对文件对象进行任何操作,则文件不会被写入磁盘,但你是对的,这有点令人困惑。我已经更改了我的示例。 - Igor Hatarist
@Kos 对不起,你是正确的,文件会更早地被创建。 - Igor Hatarist
@igor,第 file_exists 行有个错别字,那里不需要冒号 :) - cyberbemon
@IgorHatarist 非常感谢! - Sohan Das
非常感谢,它确实解决了我的问题。 - Programmer

38

另一种方式:

with open(file_path, 'a') as file:
        w = csv.DictWriter(file, my_dict.keys())

        if file.tell() == 0:
            w.writeheader()

        w.writerow(my_dict)

10
您可以检查文件是否为空。
import csv
import os

headers = ['head1', 'head2']

for row in interator:
    with open('file.csv', 'a') as f:
        file_is_empty = os.stat('file.csv').st_size == 0
        writer = csv.writer(f, lineterminator='\n')
        if file_is_empty:
            writer.writerow(headers)
        writer.writerow(row)

2
我会在编写头信息之前使用一些标志并进行检查,例如: flag
flag=0
def get_data(lst):
    for i in lst:#say list of url
        global flag
        respons = requests.get(i)
        respons= respons.content.encode('utf-8')
        respons=respons.replace('\\','')
        print respons
        data = json.loads(respons)
        fl = codecs.open(r"C:\Users\TEST\Desktop\data1.txt",'ab',encoding='utf-8')
        writer = csv.DictWriter(fl,data.keys())
        if flag==0:
            writer.writeheader()
        writer.writerow(data)
        flag+=1
        print "You have written % times"%(str(flag))
    fl.close()
get_data(urls)

1
你能否更改代码结构并一次性导出整个文件?
def write_light_csv(filename, data):
    with open (filename, 'w') as csvfile:
        headers = ['TimeStamp', 'light','Proximity']
        writer = csv.DictWriter(csvfile, delimiter=',', lineterminator='\n',fieldnames=headers)

        writer.writeheader()

        for item in data:
            if "light" in item:
                writer.writerow({'TimeStamp': item['ts'], 'light' : item['light'],'Proximity' : item['prox']})


write_light_csv('light.csv', data)

0
这是另一个仅依赖于Python内置的csv包的示例。该方法检查标题是否符合预期,否则会抛出错误。它还处理文件不存在或存在但为空的情况,通过编写标题来解决。希望这可以帮到你:
import csv
import os


def append_to_csv(path, fieldnames, rows):
    is_write_header = not os.path.exists(path) or _is_empty_file(path)
    if not is_write_header:
        _assert_field_names_match(path, fieldnames)

    _append_to_csv(path, fieldnames, rows, is_write_header)


def _is_empty_file(path):
    return os.stat(path).st_size == 0


def _assert_field_names_match(path, fieldnames):
    with open(path, 'r') as f:
        reader = csv.reader(f)
        header = next(reader)
        if header != fieldnames:
            raise ValueError(f'Incompatible header: expected {fieldnames}, '
                             f'but existing file has {header}')


def _append_to_csv(path, fieldnames, rows, is_write_header: bool):
    with open(path, 'a') as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        if is_write_header:
            writer.writeheader()
        writer.writerows(rows)


你可以使用以下代码进行测试:

file_ = 'countries.csv'
fieldnames_ = ['name', 'area', 'country_code2', 'country_code3']
rows_ = [
    {'name': 'Albania', 'area': 28748, 'country_code2': 'AL', 'country_code3': 'ALB'},
    {'name': 'Algeria', 'area': 2381741, 'country_code2': 'DZ', 'country_code3': 'DZA'},
    {'name': 'American Samoa', 'area': 199, 'country_code2': 'AS', 'country_code3': 'ASM'}
]

append_to_csv(file_, fieldnames_, rows_)


如果您运行此代码,将在 countries.csv 文件中得到以下内容:
name,area,country_code2,country_code3
Albania,28748,AL,ALB
Algeria,2381741,DZ,DZA
American Samoa,199,AS,ASM

如果你运行两次,你会得到以下结果(注意,没有第二个标题):

name,area,country_code2,country_code3
Albania,28748,AL,ALB
Algeria,2381741,DZ,DZA
American Samoa,199,AS,ASM
Albania,28748,AL,ALB
Algeria,2381741,DZ,DZA
American Samoa,199,AS,ASM

如果您更改了countries.csv文件中的标题并再次运行程序,则会收到一个值错误,如下所示:
ValueError: Incompatible header: expected ['name', 'area', 'country_code2', 'country_code3'], but existing file has ['not', 'right', 'fieldnames']

0

在使用Pandas时:用于将数据帧数据存储到CSV文件中) 如果您正在使用索引迭代API调用以将数据添加到CSV文件中,请在设置标题属性之前添加此检查。

if i > 0:
        dataset.to_csv('file_name.csv',index=False, mode='a', header=False)
    else:
        dataset.to_csv('file_name.csv',index=False, mode='a', header=True)

0

您可以使用 csv.Sniffer 类和

with open('my.csv', newline='') as csvfile:
    if csv.Sniffer().has_header(csvfile.read(1024))
    # skip writing headers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接