TypeError:当尝试写入使用bz2.BZ2File对象的csv.writer时,需要类似字节的对象,而不是'str'

kmbjn2e3  于 2023-07-31  发布在  其他
关注(0)|答案(1)|浏览(108)

背景:

我需要写一个CSV文件,我压缩,然后再放到磁盘上,因为我在SMP上同时运行大约96个进程,否则它们会填满我的小硬盘空间,然后我才能将它们卸载到其他地方(不,这不是我的系统,所以不要问我的系统,为什么一个104 CPU / 0.25TB RAM / 8特斯拉服务器只有2 TB共享给所有用户,而90%以上是满的)。我需要使用尽可能多的处理器,因为我可以,因为1个CPU将花费我近4年,并使用96下降到约2周。
类似问题的所有答案都指出您应该使用模式为'wt'的bz2.open();但是,我没有找到任何将bz 2文件类对象与csv.writer()对象一起使用地址,而且它似乎不起作用。我甚至编写了一个脚本来测试所有可能的写入模式排列(见下文),它忠实地再现了这个问题。

**注意:**我不能简单地使用','.join(row),这将过度使用mode='wt' bz 2对象,因为许多文本字段需要使用换行符,嵌入逗号,嵌入'\x00'字符等进行转义。
复制步骤:

/tmp/test.py:

import os
import bz2
import csv
import traceback

tfile = '/tmp/test.csv.bz'
row = ['bc22jtr', 118324, None, 'contran', None, 11.5, 9.23, ]

def perr(err, bmode, fmode=None):
    """Func for printing exception info in a less noisy manner."""
    print(
        f"EXCEPTION: wt.writerow(row) → {type(err).__name__}:"
        f" {err}; bmode='{bmode}', fmode='{fmode}'"
    )
    print((''.join(traceback.format_exception(err)[-2:-1])).strip())
    return True

for fmode in ["w", "wt", "wb"]:
    for bmode in ["w", "wb"]:
        had_err = False
        if os.path.exists(tfile):
            os.remove(tfile)
        fh = open(tfile, fmode)
        try:
            bh = bz2.BZ2File(fh, mode=bmode, compresslevel=9)
        except ValueError as err:
            had_err = perr(err, bmode, fmode)
        wt = csv.writer(fh)
        try:
            wt.writerow(row)
        except TypeError as err:
            had_err = perr(err, bmode, fmode)
        try:
            bh.close()
        except TypeError as err:
            had_err = perr(err, bmode, fmode)
        if not had_err:
            prnt(f"WAS OK: bmode={bmode}, fmode={fmode}")
for bmode in ["w", "wb", "wt"]:
    if os.path.exists(tfile):
        os.remove(tfile)
    bh = bz2.open(fh, mode=bmode, compresslevel=9)
    wt = csv.writer(fh)
    had_err = False
    try:
        wt.writerow(row)
    except TypeError as err:
        had_err = perr(err, bmode)
    try:
        bh.close()
    except TypeError as err:
        had_err = perr(err, bmode)
    if not had_err:
        prnt(f"WAS OK: bmode={bmode}")
if os.path.exists(tfile):
    os.remove(tfile)

字符串
输出量:

> python3 /tmp/test.py
EXCEPTION: wt.writerow(row) → TypeError: write() argument must be str, not bytes; bmode='w', fmode='w'
File "/usr/lib/python3.10/bz2.py", line 109, in close
    self._fp.write(self._compressor.flush())
EXCEPTION: wt.writerow(row) → TypeError: write() argument must be str, not bytes; bmode='wb', fmode='w'
File "/usr/lib/python3.10/bz2.py", line 109, in close
    self._fp.write(self._compressor.flush())
EXCEPTION: wt.writerow(row) → TypeError: write() argument must be str, not bytes; bmode='w', fmode='wt'
File "/usr/lib/python3.10/bz2.py", line 109, in close
    self._fp.write(self._compressor.flush())
EXCEPTION: wt.writerow(row) → TypeError: write() argument must be str, not bytes; bmode='wb', fmode='wt'
File "/usr/lib/python3.10/bz2.py", line 109, in close
    self._fp.write(self._compressor.flush())
EXCEPTION: wt.writerow(row) → TypeError: a bytes-like object is required, not 'str'; bmode='w', fmode='wb'
File "/tmp/test.py", line 33, in <module>
    wt.writerow(row)
EXCEPTION: wt.writerow(row) → TypeError: a bytes-like object is required, not 'str'; bmode='wb', fmode='wb'
File "/tmp/test.py", line 33, in <module>
    wt.writerow(row)
EXCEPTION: wt.writerow(row) → TypeError: a bytes-like object is required, not 'str'; bmode='w', fmode='None'
File "/tmp/test.py", line 49, in <module>
    wt.writerow(row)
EXCEPTION: wt.writerow(row) → TypeError: a bytes-like object is required, not 'str'; bmode='wb', fmode='None'
File "/tmp/test.py", line 49, in <module>
    wt.writerow(row)
EXCEPTION: wt.writerow(row) → TypeError: a bytes-like object is required, not 'str'; bmode='wt', fmode='None'
File "/tmp/test.py", line 49, in <module>
    wt.writerow(row)

注意:bmode='wt'不会在第一次循环中测试,因为bz2.BZ2File(fh, mode='wt')总是会引发ValueError: Invalid mode: 'wt'异常。
问题

我如何编写一个压缩的CSV文件,并在运行中进行适当的转义和编码?

wh6knrhe

wh6knrhe1#

找到答案了。你需要多个 Package 。因为我需要使用一个特殊的open函数,所以我必须有fh = open(tfile, mode='wb')行。如果你不需要这个功能,你可以跳过它,直接使用bz2.BZ2File(tfile, mode='wb', compresslevel=9)
实际上,由于必须以二进制格式打开底层文件句柄或bz2.BZ2File(),因此必须将其 Package 在io.TextIOWrapper()对象中。

import os
import bz2
import csv
import io

tfile = '/tmp/test.csv.bz'
row = ['bc22jtr', 118324, None, 'contran', None, 11.5, 9.23, ]

if os.path.exists(tfile):
    os.remove(tfile)
fh = open(tfile, mode='wb')
bz = bz2.BZ2File(fh, mode='wb', compresslevel=9)
it = io.TextIOWrapper(bz)
wt = csv.writer(it)
wt.writerow(row)

字符串

相关问题