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文件(。可能是因为Library最初是为Python 2编写的。

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

我喜欢open的方式,因为它显式且更短,OTOH如果你想处理编码错误(例如,对用户来说更好的错误(,应该使用decode/encode(可能在'n'.split(s), and keeping line numbers)之后

注意:如果你使用第一种方法(open(,你应该只使用rw,所以没有b。对于问题的标题,您似乎是正确的,但请检查您的示例是否保留了b,可能为此,它使用了encoding。OTOH的代码似乎很旧,我认为";。编码";之所以这么做,是因为在Python 2的思维方式下会更自然。

注意:我也会将strict替换为backslashreplace进行调试。您可能希望在两种方法上检查并打印(可能只是ord(self.buffer的前几个字符,看看在file.write之前是否有实质性差异。

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

Aaaan发现:Path.write_bytes()将按原样保存字节对象,而str.encoding不接触行尾。

Path.write_text()将像str.encode()一样对字节对象进行编码,但是:因为文件是在文本模式下打开的,所以在编码后,行结尾将被标准化-在我的情况下,将n转换为rn,因为我在Windows上。pdf必须使用n,无论你在哪个平台上。

最新更新