使用csv模块写入非Unicode

时间:2016-07-29 10:50:01

标签: python python-3.x csv encoding stringio

在迁移到Python 3时,我注意到我们使用内置csv生成的一些文件现在每个字符串周围都有b'前缀...

这里的代码应根据dogs定义的一些参数生成export_fields列表的.csv(因此始终返回unicode数据):

file_content = StringIO()
csv_writer = csv.writer(
    file_content, delimiter='\t', quotechar='"', quoting=csv.QUOTE_MINIMAL
)
csv_writer.writerow([
    header_name.encode('cp1252') for _v, header_name in export_fields
])
# Write content
for dog in dogs:
    csv_writer.writerow([
        get_value(dog).encode('cp1252') for get_value, _header in export_fields
    ])

问题是,一旦我返回file_content.getvalue(),我得到:

b'Does he bark?'    b'Full     Name'    b'Gender'
b'Sometimes, yes'   b'Woofy the dog'    b'Male' 

而不是 (缩进已被修改为在SO上可读)

'Does he bark?'   'Full     Name'   'Gender'
'Sometimes, yes'  'Woofy the dog'   'Male' 

我在encoding模块中找不到任何csv参数。我希望整个文件在cp1252中编码,所以我并不关心编码是通过行的迭代还是在构建的文件上完成的。

那么,有没有人知道如何生成一个合适的字符串,只包含cp1252编码的字符串?

1 个答案:

答案 0 :(得分:1)

csv模块处理文本,并使用str()将非字符串的任何内容转换为字符串。

不要传递bytes个对象。传递str对象或类型,使用str()干净地转换为字符串。这意味着你不应该编码字符串

如果您需要输出cp1252,请对StringIO值进行编码:

file_content.getvalue().encode('cp1252')

因为StringIO个对象也只处理文本。

更好的是,当csv模块写入文件对象时,使用BytesIO objectTextIOWrapper()为您进行编码:

from io import BytesIO, TextIOWrapper

file_content = BytesIO()
wrapper = TextIOWrapper(file_content, encoding='cp1252', line_buffering=True)
csv_writer = csv.writer(
    wrapper, delimiter='\t', quotechar='"', quoting=csv.QUOTE_MINIMAL)

# write rows

result = file_content.getvalue()

我已经在包装器上启用了行缓冲,这样每次写入一行时它都会自动刷新到BytesIO实例。

现在file_content.getvalue()产生一个字节串:

>>> from io import BytesIO, TextIOWrapper
>>> import csv
>>> file_content = BytesIO()
>>> wrapper = TextIOWrapper(file_content, encoding='cp1252', line_buffering=True)
>>> csv_writer = csv.writer(wrapper, delimiter='\t', quotechar='"', quoting=csv.QUOTE_MINIMAL)
>>> csv_writer.writerow(['Does he bark?', 'Full     Name', 'Gender'])
36
>>> csv_writer.writerow(['Sometimes, yes', 'Woofy the dog', 'Male'])
35
>>> file_content.getvalue()
b'Does he bark?\tFull     Name\tGender\r\nSometimes, yes\tWoofy the dog\tMale\r\n'