我使用以下代码解压缩并保存CSV文件:
with gzip.open(filename_gz) as f:
file = open(filename, "w");
output = csv.writer(file, delimiter = ',')
output.writerows(csv.reader(f, dialect='excel', delimiter = ';'))
一切似乎都正常,除了文件中的第一个字符是意外的。谷歌搜索似乎表明这是由于文件中的BOM。
我已经读到用utf-8-sig编码内容应该可以解决这个问题。但是,添加:
.read().encoding('utf-8-sig')
在 csv.reader 中到 f 失败,并显示:
File "ckan_gz_datastore.py", line 16, in <module>
output.writerows(csv.reader(f.read().encode('utf-8-sig'), dialect='excel', delimiter = ';'))
File "/usr/lib/python2.7/encodings/utf_8_sig.py", line 15, in encode
return (codecs.BOM_UTF8 + codecs.utf_8_encode(input, errors)[0], len(input))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 0: ordinal not in range(128)
如何删除 BOM 表并以正确的 utf-8 保存内容?
首先,您需要解码文件内容,而不是对其进行编码。
其次,csv
模块不喜欢 Python 2.7 中的 unicode 字符串,因此解码数据后,您需要转换回 utf-8。
最后,csv.reader
传递文件行上的迭代,而不是包含换行符的大字符串。
所以:
csv.reader(f.read().decode('utf-8-sig').encode('utf-8').splitlines())
但是,您可能会认为手动删除 BOM 更简单/更有效:
def remove_bom(line):
return line[3:] if line.startswith(codecs.BOM_UTF8) else line
csv.reader((remove_bom(line) for line in f), dialect = 'excel', delimiter = ';')
这是微妙的不同,因为它从任何以 BOM 开头的行中删除 BOM,而不仅仅是第一行。如果您不需要保留其他 BOM,那没关系,否则您可以使用以下方法修复它:
def remove_bom_from_first(iterable):
f = iter(iterable)
firstline = next(f, None)
if firstline is not None:
yield remove_bom(firstline)
for line in f:
yield f