首页 > 解决方案 > open(..., encoding="") vs str.encode(encoding="")

问题描述

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

上下文:
在使用PyFPDF(版本 1.7.2)时,我对类进行了子FPDF类化,除其他外,添加了我自己的输出方法(获取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() 是相同的.

注意: FPDF.buffer是 类型str,但包含二进制数据(pdf 文件)。可能是因为该库最初是为 Python 2 编写的。

标签: pythonpython-3.xcharacter-encodingpyfpdf

解决方案


两者应该相同(有细微差别)。

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

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

注意:我也将替换strictbackslashreplace进行调试。并且可能您可能想要检查并打印(可能只是 ord)self.buffer这两种方法的前几个字符,以查看之前是否存在实质性差异file.write

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


推荐阅读