来源:未闻Code 我们常常需要在 Python 中输出 CSV 文件,但你可能会发现,这些输出的 CSV文件,不能双击使用 Excel 打开,否则中文会变成乱码。例如下面这段代码: import pandas as pd
datas = [
{
'name': '王小一',
'age': 29,
'address': '北京'
},
{
'name': '张小二',
'age': 18,
'address': '四川'
},
{
'name': '李小三',
'age': 60,
'address': '上海'
}
]
df = pd.DataFrame(datas)
df.to_csv('person.csv', index=False)
如果双击使用 Excel 打开,你会发现中文变成了乱码,如下图所示: 
这是因为,当你执行代码 df.to_csv('person.csv',index=False) 时,它默认会以 UTF-8编码方式写 CSV 文件。但是当你双击 CSV 使用 Excel打开时,Excel 会以 GBK 编码来读这个文件,这就导致了乱码的发生。 所以,如果是简单的中文,你可以把编码方式人工指定为 GBK: import pandas as pd
datas = [
{
'name': '王小一',
'age': 29,
'address': '北京'
},
{
'name': '张小二',
'age': 18,
'address': '四川'
},
{
'name': '李小三',
'age': 60,
'address': '上海'
}
]
df = pd.DataFrame(datas)
df.to_csv('person.csv', index=False, encoding='gbk')
此时再双击使用 Excel 打开,中文就能正常显示了,如下图所示: 
但 GBK 编码的字符集不够完善,所以如果文本中包含超出 GBK 字符集的内容,就会导致编码错误,如下图所示: 

这个时候怎么办呢? 实际上当你双击打开 CSV 的时候,Excel会检查文件的第一个字符,如果这个字符是 BOM,那么他就知道应该使用 UTF-8编码方式来打开这个文件。所谓的 BOM 指的是 byte-order mark 。 BOM 对应的 Unicode 码为 \ufeff ,所以当我们使用 UTF-8编码方式生成 CSV 以后,再增加一步,把 BOM 写入到文件的第一个字符:
with open('person.csv', encoding='utf-8') as f:
content = f.read()
content_with_bom = '\ufeff' + content
with open('person.csv', 'w', encoding='utf-8') as f:
f.write(content_with_bom)
完整代码如下图所示: 
此时,新的 CSV 文件可以直接双击通过 Excel 打开,并且中文支持完全正常,如下图所示: 
这样生成的 Excel 虽然在 Excel 上显示没有问题,但是如果你发给别人,别人使用 Python 自带的 csv 模块打开,就会发现 address 这一列的列名不是 address 而是 \ufeffaddress ,如下图所示: 
这个 BOM 字符虽然肉眼看不到,但是程序能够看到,这就会导致别人在读这个 CSV 文件的时候非常不方便。如果直接使用 address 去读,还会报错: 
难道此时,需要先用普通方式读取 csv 文件,移除第一个 BOM 字符,然后再传给 CSV 模块吗?这未免太过麻烦。 好在 Python 只带了处理 BOM 的编码方式 utf-8-sig ,无论是写文件还是读文件,只要使用这个编码方式,Python 在写文件的时候会自动加上 BOM,在读文件的时候会自动删除 BOM。 所以生成 CSV 文件的代码如下: import pandas as pd
datas = [
{
'name': '王小一',
'age': 29,
'address': '北京'
},
{
'name': '张小二',
'age': 18,
'address': '四❤川'
},
{
'name': '李小三',
'age': 60,
'address': '上海'
}
]
df = pd.DataFrame(datas)
df.to_csv('person.csv', index=False, encoding='utf-8-sig')
此时生成的 CSV 文件,可以直接双击使用 Excel 打开,中文正常显示。 如果要使用 Python 的 CSV 模块读取文件,也非常简单,如下图所示: 
读取出来的内容直接使用,BOM 已经被 Python 自动移除了。
|