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

Posted

技术标签:

【中文标题】r 和 rb 模式下解析文本文件的区别【英文标题】:Difference between parsing a text file in r and rb mode 【发布时间】:2012-03-27 11:56:09 【问题描述】:

是什么让在 'r' 模式下解析文本文件比在 'rb' 模式下解析更方便? 尤其是当相关文本文件可能包含非 ASCII 字符时。

【问题讨论】:

你读的是文本文件还是二进制文件? 一个文本文件。但无论出于何种原因,我都将文件作为字节流提供。 【参考方案1】:

来自documentation:

在 Windows 上,附加到模式的 'b' 以二进制模式打开文件,因此还有 'rb'、'wb' 和 'r+b' 等模式。 Windows 上的 Python 区分了文本文件和二进制文件;读取或写入数据时,文本文件中的行尾字符会自动稍作更改。这种对文件数据的幕后修改适用于 ASCII 文本文件,但它会破坏 JPEG 或 EXE 文件中的二进制数据。在读写此类文件时要非常小心使用二进制模式。在 Unix 上,将 'b' 附加到模式并没有什么坏处,因此您可以独立于平台使用它来处理所有二进制文件。

【讨论】:

所以基本上尝试以二进制模式读取行要困难得多,因为我不能保证 EOL 字符是 \n 或 \r\n 或其他?【参考方案2】:

这在一定程度上取决于您使用的 Python 版本。在 Python 2 中,Chris Drappier's answer 适用。

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

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

【讨论】:

对于py3,在文本模式下阅读会自动尝试检测它是什么类型的编码吗?我想必须检测编码对于字节对象来说是一个相当大的挑战。 @Keikoku 仅基于流检测编码,没有任何元数据,是不可能的 - 考虑 ASCII 的各种编码 + 使用第 8 位作为信息而不是奇偶校验;它们都共享 255 个有效的单字节序列,但它们中只有一半(ASCII 的一半)在每个中表示相同的字符。 Python 的默认值不是猜测它,它是一个会话范围的默认编码,拼写为sys.getdefaultencoding()。在我的 Py3 安装中,它是 UTF-8,但你不能总是这样。【参考方案3】:

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

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

Python 也有一个通用的换行模式。在此模式下打开文件时,Python 会将所有字符 \r\n\r\n 映射到 \n

【讨论】:

Python 2 和 Python 3 都是这样吗?【参考方案4】:

为了澄清和回答Agostino's comment/question(我没有足够的声誉发表评论,所以请耐心等待我将其作为答案......):

在 Python 2 中,无论是文本模式还是二进制模式,都不会发生行尾修改 - 如前所述,在 Python 2 Chris Drappier's answer 中适用(请注意,它现在的链接指向 3.x Python 文档,但 Chris'引用的文字当然来自Python 2 input and output tutorial)

所以不,不是真的,在非 Windows 上使用 Python 2text 模式打开文件会进行任何行结束修改

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()'

然而,可以在 Python 2 中以通用换行模式打开文件,它确实执行所述行结束模式:

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-line-ended 文件会将行尾规范化为 '\n'。

【讨论】:

Python3 的 open 函数有一个换行参数来控制是否需要 docs.python.org/3/library/functions.html#open "newline 控制通用换行模式如何工作(它只适用于文本模式)。它可以是 None, '', '\ n', '\r', 和'\r\n'。它的工作原理如下:从流中读取输入时,如果换行符为None,则启用通用换行符模式”

以上是关于r 和 rb 模式下解析文本文件的区别的主要内容,如果未能解决你的问题,请参考以下文章

文件对象中的rb和r+b模式有啥区别

文件操作

回车换行符

python -- 文件处理

非文本文件 读取

文件读写’r'和’rb’区别