python - 在 Python 中从 gzip 压缩的 CSV 中删除 BOM

标签 python csv byte-order-mark

我正在使用以下代码解压缩并保存 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 = ';')

这略有不同,因为它会从任何以 one 开头的行中删除 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

关于python - 在 Python 中从 gzip 压缩的 CSV 中删除 BOM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20899939/

相关文章:

python - 使用类属性作为函数参数?

python - 猴子修补 'datetime' 产生奇怪的结果

python - 如何仅给出长度递归地构建列表?

php - 从 HTML 表单解析 CSV 并插入 MYSQL 数据库

html - Twitter Bootstrap 生成空白空间

haskell - 从 Haskell ByteString 中删除 BOM 的最简单方法

c# - X文档 : saving XML to file without BOM

Python代码没有给出

mysql - 用 CSV 文件中的数据填充 MySQL 表

mysql - Csv 希伯来文文本顺序不正确