R 和 rb 模式下解析文本文件的区别

是什么使得在‘ r’模式下解析文本文件比在‘ rb’模式下更方便? 特别是当有问题的文本文件可能包含非 ASCII 字符时。

90097 次浏览

来自 文件:

在 Windows 中,模式后面的“ b”以二进制模式打开文件,因此也有类似于“ rb”、“ wb”和“ r + b”的模式。Windows 上的 Python 对文本文件和二进制文件进行了区分; 当读取或写入数据时,文本文件中的行尾字符会自动略微改变。这种对文件数据的幕后修改对于 ASCII 文本文件来说没有问题,但是会破坏 JPEG 或 EXE 文件中的二进制数据。在读写这类文件时,一定要非常小心地使用二进制模式。在 Unix 上,在模式中添加一个“ b”不会有什么坏处,所以您可以在平台上独立地使用它来处理所有二进制文件。

这在一定程度上取决于您使用的是哪个版本的 Python。

在 Python 3中,这是一个不同的(而且更一致的)故事: 在文本模式('r')中,Python 将根据您提供的文本编码来解析文件(或者,如果您没有提供文本编码,则使用平台相关的默认值) ,而 read()将提供一个 str。在二进制('rb')模式下,Python 不假定文件包含可以合理解析为字符的内容,而 read()提供了一个 bytes对象。

此外,在 Python 3中,通用换行符('\n'和特定于平台的换行符约定之间的转换,因此您不必关心它们)可用于 任何平台上的文本模式文件,而不仅仅是 Windows。

区别在于如何处理行尾(EOL)。不同的操作系统使用不同的字符在 Unix 中标记 EOL-\n,在 OS X 之前的 Mac 版本中标记 \r,在 Windows 中标记 \r\n。当以文本模式打开文件时,当文件被读取时,Python 仅用 \n替换从文件中读取的操作系统特定的行尾字符。反之亦然,也就是说,当您尝试将 \n写入以文本模式打开的文件时,它将写入特定于操作系统的 EOL 字符。你可以通过检查 os.linesep找到你的操作系统默认的 EOL。

当以二进制模式打开文件时,不进行映射。你读到的就是你得到的。记住,文本模式是默认模式。因此,如果您正在处理非文本文件(图像、视频等) ,请确保您以二进制模式打开该文件,否则您最终会因引入(或删除)一些字节而弄乱该文件。

Python 还有一个通用的 newline 模式。当以这种模式打开文件时,Python 将所有字符 \r\n\r\n映射到 \n

为了澄清和回答 Agostino 的评论/问题(我没有足够的声誉来评论,所以请容忍我把这作为一个答案...) :

在 Python 2中,不会发生行尾修改,无论是在文本模式还是二进制模式下——正如之前所说,在 Python 2 Chris Drappier 的回答中适用(请注意,它的链接现在指向3.x Python 文档,但 Chris 引用的文本当然来自 Python 2输入输出教程)

所以,在使用 Python2非视窗短信模式打开一个文件时,行尾的任何修改都是正确的:

0 $ cat data.txt
line1
line2
line3
0 $ file data.txt
data.txt: ASCII text, with CRLF line terminators
0 $ python2.7 -c 'f = open("data.txt"); print f.readlines()'
['line1\r\n', 'line2\r\n', 'line3\r\n']
0 $ python2.7 -c 'f = open("data.txt", "r"); print f.readlines()'
['line1\r\n', 'line2\r\n', 'line3\r\n']
0 $ python2.7 -c 'f = open("data.txt", "rb"); print f.readlines()'

然而,在 Python2中以通用换行模式打开文件是可能的,它确实执行了上述行结束模式:

0 $ python2.7 -c 'f = open("data.txt", "rU"); print f.readlines()'
['line1\n', 'line2\n', 'line3\n']

(在 Python 3. x 中,通用换行模式说明符已被弃用)

另一方面,在 Python 3中,当以文本模式读取文件时,特定于平台的行结束符被标准化为‘ n’,而当以文本模式写入时,‘ n’被转换为当前平台的默认行结束符(除了以文本模式进行的字节 <-> unicode <-> 字节解码/编码)。例如,在 Linux 上读取 Dos/Win CRLF 行结束文件将使行结束标准化为“ n”。