背景:
我需要写一个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文件,并在运行中进行适当的转义和编码?
1条答案
按热度按时间wh6knrhe1#
找到答案了。你需要多个 Package 。因为我需要使用一个特殊的open函数,所以我必须有
fh = open(tfile, mode='wb')
行。如果你不需要这个功能,你可以跳过它,直接使用bz2.BZ2File(tfile, mode='wb', compresslevel=9)
。实际上,由于必须以二进制格式打开底层文件句柄或
bz2.BZ2File()
,因此必须将其 Package 在io.TextIOWrapper()
对象中。字符串