如何在Python3中将UTF-8 CSV写入BytesIO?

Nei*_*ski 6 stringio python-3.x

首先,我了解如何在 Python3 中从字符串编写 UTF-8,并且StringIO推荐用于此类字符串构建。但是,我特别需要一个类似二进制文件的对象,为此我需要BytesIO. 如果我执行以下操作,那么数据最终会崩溃,因为它被读取为Latin1,我的计算机的默认区域设置/字符集。

with io.StringIO() as sb:
    csv.writer(sb).writerows(rows)
    sb.flush()
    sb.seek(0)
    # blows up with Latin1 encoding error
    job = bq.load_table_from_file(sb, table_ref, job_config=job_config)
Run Code Online (Sandbox Code Playgroud)

所以我的解决方法是这个怪物,使内存使用量加倍:

with io.StringIO() as sb:
    csv.writer(sb).writerows(rows)
    sb.flush()
    sb.seek(0)
    with io.BytesIO(sb.getvalue().encode('utf-8')) as buffer:
        job = bq.load_table_from_file(buffer, table_ref, job_config=job_config)
Run Code Online (Sandbox Code Playgroud)

在此链中的某个位置必须有一种方法来指定字节编码,以便类似文件的读者sb将看到 UTF-8 格式的数据。或者有没有办法使用csv.writer()字节流?

我在 StackOverflow 上寻找了这两个答案,但我发现的通常是写入文件和内存中所有内容都指向的内容StringIO

Nei*_*ski 6

有一个TextIOWrapper类可以完成这项工作,但是如果您使用上下文管理器,with那么它将关闭流并使原始BytesIO对象无法使用。

修改我原来的例子:

with io.BytesIO() as buffer:
    sb = io.TextIOWrapper(buffer, 'utf-8', newline='')
    csv.writer(sb).writerows(rows)
    sb.flush()
    buffer.seek(0)
    job = bq.load_table_from_file(buffer, table_ref, job_config=job_config)
Run Code Online (Sandbox Code Playgroud)

另一个需要注意的是该newline参数,如果单独保留,则会转换换行符。设置newline = ''以防止这种情况发生。