打开(...,编码=“”)与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.buffer
是 str
类型,但包含二进制数据(pdf 文件)。可能是因为库最初是为 Python 2.
编写的
两者应该相同(略有不同)。
我喜欢 open
方式,因为它明确且更短,OTOH 如果你想处理编码错误(例如,一种更好的用户错误方式),应该使用 decode
/encode
(也许在 '\n'.split(s), and keeping line numbers)
之后
注意:如果您使用第一种方法(open
),您应该只使用r
或w
,而不用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
,无论您使用什么平台。
问题:
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.buffer
是 str
类型,但包含二进制数据(pdf 文件)。可能是因为库最初是为 Python 2.
两者应该相同(略有不同)。
我喜欢 open
方式,因为它明确且更短,OTOH 如果你想处理编码错误(例如,一种更好的用户错误方式),应该使用 decode
/encode
(也许在 '\n'.split(s), and keeping line numbers)
注意:如果您使用第一种方法(open
),您应该只使用r
或w
,而不用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
,无论您使用什么平台。