何时需要以二进制模式(b)打开文件?

20

我在文档中注意到他们总是用'wb'打开CSV文件。那个'b'是什么意思呢?我知道'b'代表二进制模式,但什么时候使用二进制模式(CSV文件不是二进制文件)。如果相关的话,我是通过arcpy.da.SearchCursor()查询结果将数据写入CSV文件中。

编辑:刚刚注意到根据这个答案,使用wb+来写入二进制文件。包含'+'号又是什么意思呢?


1
如果有任何非ASCII字符,您应该使用二进制模式进行打开。据我所知,在二进制模式下打开永远不会改变或损坏您的数据,但是有时在ASCII模式下打开会删除或更改字符。因此,我总是使用二进制模式打开(即使是ASCII数据)。 - Joran Beasley
1
@JoranBeasley:并不存在“ASCII模式”这样的说法。请使用“文本模式”代替(文本文件的字符编码可以是任何东西)。 - jfs
1
阅读您链接的问题的答案(https://dev59.com/0mQo5IYBdhLWcg3wQNX4) -- + 表示您既想从文件中写入又想读取。 - jfs
6个回答

15
使用'b'模式,以二进制数据的形式读写,不进行任何转换,例如将换行符转换为/从特定于平台的值或使用字符编码解码/编码文本。

csv 模块是特殊的。csv 数据是文本数据,因此应该使用文本模式,但是 csv 模块默认使用 '\r\n' 在所有平台上终止行,并且 它总是将 '\r''\n' 都识别为换行符。如果您在文本模式下打开相应的文件(使用 通用换行符),则在 Windows 上会得到 '\r\r\n'(破损的换行符)(os.linesep == '\r\n')。这就是 Python 2 文档中说必须使用二进制模式的原因。在 Python 3 中,使用文本模式,但应传递 newline='' 来禁用 通用换行符 模式。 如果要保留字段中嵌入的可能的换行符(如 '\r'),还应禁用通用换行符。


严格来说,传递 newline='' 不会禁用通用换行模式。根据文档:“如果它是'', 通用换行模式被启用,但行尾不会被转换为调用者的格式。” - user_

6
文件默认以文本模式打开,这可能会在写入时将'\n'字符转换为特定于平台的表示形式,并在读取时进行还原。在Windows中,这将修改换行符从'\n'到'\r\n',这将导致在其他应用程序/平台上打开CSV文件时出现问题。
因此,在打开二进制文件时,应将'b'附加到模式值以以二进制模式打开文件,这将提高可移植性。在没有此区别的系统上,添加'b'没有效果。
注意:'w+'截断文件。
'r+'、'w+'和'a+'模式打开文件以进行更新(读取和写入)。
如此详细地介绍:https://docs.python.org/2/library/functions.html#open

“截断”文件是什么意思?它是否意味着替换? - Celeritas
这恰恰相反。 文本模式增加了代码的可移植性(您可以阅读在其他平台上编写的文本,使用特定于平台的程序(例如notepad.exe)来理解本地文件)。csv是一个特例,在文本数据中使用二进制模式 - jfs
截断意味着如果文件不存在,则会创建该文件,如果文件存在,则会被覆盖。因此,简单来说,它的意思是替换。 - CodePick
我同意,“文本模式增加了可移植性,CSV只是一种特殊情况,在其中二进制模式用于文本数据”。 - CodePick

1
在非Posix环境(如MSDOS和MS Windows)上使用t时,\r\n序列在输入时转换为\n(输出时相反)。b(二进制模式)不执行此类转换。CSV库可能通过忽略回车符号(每当遇到回车符号时)来处理它们。

编辑:刚注意到问题有所更改。

由于CSV文件并不是为人类读者而设计的,因此该库可以仅使用\n(换行符LF)分隔符输出它们。唯一的真正缺点是MSWindows用户使用记事本打开文件时会显示不佳。CSV库还可以输出带有\r\n(CR LF)的文件,因为大多数程序都防御MSDOS文本文件约定。

无论哪种方式,该库都可以通过b(二进制)模式良好地进行写入。如果以t(文本)模式打开,则行分隔符可能会出现像\r\n\n这样稍微奇怪的东西。可能大多数CSV文件解析器会忽略CR,并认为LF LF表示结束一行,并跟随一个空(空白)行,它也将忽略它。

+man page中有解释:

w+      可读可写模式。 如果文件不存在,则创建该文件,否则将截断该文件。 流定位在文件开头。

w不同之处在于,w+允许读取和写入。


1
可能通过将它们用作行分隔符(\n)来解决...不过这是一个好答案。 - Joran Beasley
无论在文本模式下是否翻译 '\r\n' 都取决于平台(os.linesep)。在 Windows 上是这样的,在 OS X 上则不是。您不需要显式使用 't' 模式(它会在 Python 2 的 stdio 函数中传递,因此可能会启用平台相关的行为,例如将 Ctrl+Z 识别为输入的 EOF 字符)。csv 模块始终在输入时识别 '\r' 和 '\n' - jfs

0

我从未得到过为什么不应该以二进制模式打开 ASCII 文件的好解释。

我从未见过以二进制模式打开文件会破坏数据。

我曾经见过在 ASCII 模式下打开文件修改或损坏检索到的数据,因此我以及我认为大多数经验丰富的 Python 程序员通常会以二进制模式打开文件,除非我们有某种保证文件中没有并且永远不会有二进制字符。


要理解原因,请编写 open('binary.txt', 'wb').write(b"1\n2\n3\n")open('text.txt', 'w').write("1\n2\n3\n") 并尝试在 notepad.exe 中打开这两个文件。 - jfs
因为记事本.exe太蠢了,无法识别未在其前面加上\r的\n作为换行符,这并不是一个好的理由...如果我写"\n",我希望文件中只包含\n... - Joran Beasley

0

在文本模式下打开文件会根据操作系统的不同处理换行符,因此CVS例程的作者必须确定他们想要更多的控制权 - 他们更愿意自己处理换行符。这可能使他们能够解决在一个操作系统下处理在另一个操作系统上创建的文件时遇到的不一致性问题 -- 在某些独特情况下,“文本读取”会导致问题。也可能没有发现错误,但他们想要避免未来的可能性。或者,由于他们必须处理换行符考虑,绕过文本处理可能会更快。

从逻辑上讲,由于无法控制正在读取的文件的操作系统源,因此使用二进制可能是一般情况下更好的选择。然而,写入文本文件时,最好使用文本模式,让核心例程处理当前操作系统的换行符。

“+”在Confused by python file mode "w+"中有所讨论。


-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接