【发布时间】:2011-03-16 12:45:40
【问题描述】:
我知道我应该使用"rb" 而不是"r" 打开一个二进制文件,因为Windows 对于二进制文件和非二进制文件的行为不同。
但是我不明白如果我以错误的方式打开文件会发生什么,以及为什么这种区分是必要的。其他操作系统似乎可以通过将这两种文件同等对待。
【问题讨论】:
标签: python windows file file-io
我知道我应该使用"rb" 而不是"r" 打开一个二进制文件,因为Windows 对于二进制文件和非二进制文件的行为不同。
但是我不明白如果我以错误的方式打开文件会发生什么,以及为什么这种区分是必要的。其他操作系统似乎可以通过将这两种文件同等对待。
【问题讨论】:
标签: python windows file file-io
此模式是关于行尾的转换。
在文本模式下阅读时,平台的本机行尾(Windows 上的\r\n)会转换为 Python 的 Unix 风格的 \n 行尾。在文本模式下书写时,会发生相反的情况。
在二进制模式下,不会进行这种转换。
其他平台通常在没有转换的情况下也可以正常工作,因为它们将行结尾本地存储为 \n。 (Mac OS 是个例外,过去使用 \r。)然而,依赖于此的代码不可移植。
【讨论】:
在 Windows 中,文本模式会将换行符 \n 转换为回车符,然后是换行符 \r\n。
如果您以二进制模式阅读文本,则没有问题。如果你在文本模式下读取二进制数据,它可能会被损坏。
【讨论】:
对于读取文件应该没有区别。当写入文本文件时,Windows 会自动弄乱你的换行符(它会在\n 之前添加\r)。这就是为什么你应该使用"wb"。
【讨论】:
这是出于历史原因(或者我喜欢说,歇斯底里)。文件打开模式继承自 C stdio 库,因此我们遵循它。
对于 Windows,文本和二进制文件之间没有区别,就像在任何 Unix 克隆中一样。不,我是认真的! - 有(有)文件系统/操作系统,其中文本文件与目标文件完全不同,等等。在某些情况下,您必须提前指定行的最大长度并使用固定大小的记录......来自 80 列纸质穿孔卡片等时代的化石。幸运的是,在 Unices、Windows 和 Mac 中并非如此。
但是 - 所有其他条件都相同 - Unix、Windows 和 Mac 历史上 不同之处在于它们在输出流中使用哪些字符来标记一行的结尾(或者,同样的事情,作为行之间的分隔符)。在 Unix 中,使用 \x0A (\n)。在 Windows 中,使用两个字符的序列 \x0D\x0A (\r\n);在 Mac 上 - 只需 \xOD (\r)。以下是关于这两个符号的使用来源的一些线索 - ASCII 代码 10 被称为 换行 (LF),当发送到电传打字机时,会导致它向下移动一行 (Y++),没有改变其水平 (X) 位置。 回车 (CR) - ASCII 13 - 另一方面,将导致打印回车返回到行首 (X=0) 而无需向下滚动一行。因此,在向打印机发送输出时,必须同时发送 \r 和 \n,以便托架将移动到新行的开头。现在,在终端键盘上打字时,自然希望操作员按一个键,而不是按两个键。 Apple 上的那个][ 是键 'Return' (\r)。
无论如何,事情就是这样解决的。 C 的创建者担心可移植性——大部分 Unix 是用 C 编写的,不像以前,操作系统是用汇编程序编写的。所以他们不想处理每个平台关于文本表示的怪癖,所以他们根据平台将这个邪恶的黑客添加到他们的 I/O 库中,该文件的输入和输出将被即时“修补”,以便程序将看到 righteous 的新行,Unix 方式 - 为 '\n' - 无论它是来自 Windows 的 '\r\n' 还是来自 Mac 的 '\r'。所以开发者不必担心程序运行的是什么操作系统,它仍然可以读写原生格式的文本文件。
但是有一个问题 - 并非所有文件都是文本,还有其他格式,并且它们对用另一个字符替换一个字符非常敏感。因此,尽管如此,我们将调用这些“二进制文件”并通过在模式中包含“b”来指示fopen() - 这将标记库不进行任何幕后转换。这就是它的样子:)
所以回顾一下,如果文件在二进制模式下使用“b”打开,则不会发生任何转换。如果它以文本模式打开,根据平台的不同,可能会发生一些换行符的转换——从 Unix 的角度来看。自然,在 Unix 平台上,读/写“文本”或“二进制”文件没有区别。
【讨论】:
EOF,即 -1 - 类型为 int 而不是 char。在 Windows 上不是这样,它不会从终端翻译 ^Z - 而是 getchar() 实现在文本模式下将其翻译为 EOF