打开(...,编码=“”)与str.encode(编码=“”)

open(..., encoding="") vs str.encode(encoding="")

问题:
open(<name>, "w", encoding=<encoding>)open(<name>, "wb") + str.encode(<encoding>) 有什么区别?它们似乎(有时)产生不同的输出。

上下文:
在使用 PyFPDF(版本 1.7.2)时,我对 FPDF class 进行了子class,除此之外,还添加了我自己的输出方法(采用 pathlib.Path 对象)。在查看原始 FPDF.output() 方法的源代码时,我注意到几乎所有内容都是参数解析 - 唯一相关的位是

#Finish document if necessary
if(self.state < 3):
    self.close()
[...]
f=open(name,'wb')
if(not f):
    self.error('Unable to create output file: '+name)
if PY3K:
    # manage binary data as latin1 until PEP461 or similar is implemented
    f.write(self.buffer.encode("latin1"))
else:
    f.write(self.buffer)
f.close()

看到那个,我自己的实现是这样的:

def write_file(self, file: Path) -> None:
    if self.state < 3:
        # See FPDF.output()
        self.close()
    file.write_text(self.buffer, "latin1", "strict")

这似乎有效 - 在指定路径创建了一个 .pdf 文件,chrome 打开了它。但它是完全空白的,即使我添加了图像和文本。经过几个小时的试验,我终于找到了一个有效的版本(生成了一个非空的 pdf 文件):

def write_file(self, file: Path) -> None:
    if self.state < 3:
        # See FPDF.output()
        self.close()
    # using .write_text(self.buffer, "latin1", "strict") DOES NOT WORK AND I DON'T KNOW WHY
    file.write_bytes(self.buffer.encode("latin1", "strict"))

查看 pathlib.Path 来源,它使用 io.open 代替 Path.write_text()。由于所有这些都是 Python 3.8,io.open 和构建 open() are the same.

注: FPDF.bufferstr 类型,但包含二进制数据(pdf 文件)。可能是因为库最初是为 Python 2.

编写的

两者应该相同(略有不同)。

我喜欢 open 方式,因为它明确且更短,OTOH 如果你想处理编码错误(例如,一种更好的用户错误方式),应该使用 decode/encode(也许在 '\n'.split(s), and keeping line numbers)

之后

注意:如果您使用第一种方法(open),您应该只使用rw,而不用b。对于您的问题的标题,您似乎是正确的,但请检查您的示例是否保留了 b,并且可能为此使用了 encoding。 OTOH 代码看起来很旧,我认为“.encoding”刚刚完成,因为它在 Python2 心态中会更自然。

注意:我也会将 strict 替换为 backslashreplace 以进行调试。并且可能您可能想要在两种方法上检查和打印 self.buffer 的前几个字符(也许只是排序),以查看 file.write.

之前是否存在实质性差异

我会在这两个函数上添加一个 file.flush()。这是区别之一:缓冲不同,我会确保关闭文件。 Python 会这样做,但是在调试时,重要的是尽快查看文件的内容(以及在异常之后)。垃圾收集器无法保证这一切。也许您正在阅读尚未刷新的文本文件。

Aaaand 发现:Path.write_bytes() 将按原样保存字节对象,并且 str.encoding 不会触及行结尾。

Path.write_text() 将像 str.encode() 一样对字节对象进行编码,但是:因为文件是在 text[=24 中打开的=] 模式,行结尾将在 编码后被规范化 - 在我的例子中将 \n 转换为 \r\n 因为我在 Windows。 pdf 必须使用 \n,无论您使用什么平台。