csv 类编写器:需要类似字节的对象,而不是“str”

FSR*_*byc 5 python csv design-patterns

对于个人项目,我正在尝试将paterns包升级到 Python 3。实际上我正在运行 test:db.py,但我在 csv 上的“__init__.py”文件中遇到以下错误班级:

这是save()函数的代码片段:在那里,我们将s定义为BytesIO()流,因此要求该函数将字节流式传输到自身的csv 文件。该错误来自以下行:

w.writerows([[csv_header_encode(name, type) for name, type in self.fields]])

TypeError: a bytes-like object is required, not 'str' ( below, also the code for this function)
Run Code Online (Sandbox Code Playgroud)

假设 csv_header_encode 传递字节,我检查了这一点,它确实如此,但不知何故,在其转换为列表时,它更改为“str”。如果我将s编码更改为 StringsIO 那么抱怨来自

 f.write(BOM_UTF8)
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。

def save(self, path, separator=",", encoder=lambda v: v, headers=False, password=None, **kwargs):
    """ Exports the table to a unicode text file at the given path.
        Rows in the file are separated with a newline.
        Columns in a row are separated with the given separator (by default, comma).
        For data types other than string, int, float, bool or None, a custom string encoder can be given.
    """
    # Optional parameters include all arguments for csv.writer(), see:
    # http://docs.python.org/library/csv.html#csv.writer
    kwargs.setdefault("delimiter", separator)
    kwargs.setdefault("quoting", csvlib.QUOTE_ALL)
    # csv.writer will handle str, int, float and bool:
    s = BytesIO()
    w = csvlib.writer(s,  **kwargs)
    if headers and self.fields is not None:
        w.writerows([[csv_header_encode(name, type) for name, type in self.fields]])
    w.writerows([[encode_utf8(encoder(v)) for v in row] for row in self])
    s = s.getvalue()
    s = s.strip()
    s = re.sub("([^\"]|^)\"None\"", "\\1None", s)
    s = (s if not password else encrypt_string(s, password)).encode('latin-1')
    f = open(path, "wt")
    f.write(BOM_UTF8)
    f.write(s)
    f.close()

def csv_header_encode(field, type=STRING):
    # csv_header_encode("age", INTEGER) => "age (INTEGER)".
    t = re.sub(r"^varchar\(.*?\)", "string", (type or ""))
    t = t and " (%s)" % t or ""
    return "%s%s" % (encode_utf8(field or ""), t.upper())
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 3

您可能正在尝试写入BytesIO对象,但仅csv.writer()处理字符串。来自csvwriter 对象文档

\n\n
\n

行必须是字符串或数字的可迭代对象

\n
\n\n

强调我的。csv.writer()还需要一个要写入的文本文件;该对象产生字符串:

\n\n
\n

[...] 将 user\xe2\x80\x99s 数据转换为给定类文件对象上的分隔字符串。

\n
\n\n

要么使用io.StringIO对象,要么将BytesIO对象包装在io.TextIOWrapper对象中来为您处理编码。无论哪种方式,您都需要将 Unicode 文本传递给csv.writer().

\n\n

因为稍后您再次将s.getvalue()数据视为字符串(使用定义为字符串的正则表达式,并使用 Latin-1 编码),所以您可能想要写入文本文件 (so StringIO)。

\n\n

失败f.write(BOM_UTF8)是一个单独的问题f以文本模式 ( ) 打开\'wt\',因此需要字符串,而不是bytes。如果要将 \n 文本写入以 UTF-8 编码且开头带有 UTF-8 BOM 的文件,则可以utf-8-sig在打开文件时使用该编码:

\n\n
open(path, \'w\', encoding=\'utf-8-sig\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

一般来说,您似乎以所有错误的方式混合字节和字符串。尽可能长时间地将文本保留为文本,并且仅在最后可能的时刻进行编码。此时此刻是在 location 处写入文件时path,您可以将编码完全留给文件对象。

\n