【问题标题】:Write non-Unicode using csv module使用 csv 模块编写非 Unicode
【发布时间】:2016-12-04 01:28:14
【问题描述】:

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

这里的代码应该根据export_fields 定义的一些参数为dogs 列表生成一个.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' 

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

那么,有谁知道如何生成一个正确的字符串,只包含 cp1252 编码的字符串?

【问题讨论】:

  • 你为什么要编码?打开的文件对象负责处理。
  • @MartijnPieters 也许我的问题不完整:我想通过 Django 返回字符串:return HttpResponse(generate_csv_file())。我应该在 Django 级别处理编码吗?
  • 看我的回答;你在错误的水平上接近这个;制表符和引号字符也需要编码,但这是 I/O 级别的工作,而不是 csv 模块或生成行的代码。

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


【解决方案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'

【讨论】:

  • 看起来它确实适用于包装器(一旦刷新,但您在我有时间发表评论之前进行了编辑)。测试通过了,所以 99% 确定它是正确的答案 :)
  • @MaximeLorant:我现在已将其切换为使用行缓冲;避免手动冲洗。对此感到抱歉。
  • 确实看起来更干净!感谢您的提示。
猜你喜欢
  • 2020-02-15
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 2015-01-22
  • 2020-09-27
  • 1970-01-01
  • 2013-08-29
  • 2012-01-04
相关资源
最近更新 更多