Python在Windows中写入时会用"\r\n"替换"\n"

15

在研究了我的问题(链接)之后,我发现它是由一个更简单的问题引起的。

当我向文件写入"\n"时,我期望从文件中读取"\n"。但在Windows中情况并非总是如此。

In [1]: with open("out", "w") as file:
   ...:     file.write("\n")
   ...:

In [2]: with open("out", "r") as file:
   ...:     s = file.read()
   ...:

In [3]: s  # I expect "\n" and I get it
Out[3]: '\n'

In [4]: with open("out", "rb") as file:
   ...:     b = file.read()
   ...:

In [5]: b  # I expect b"\n"... Uh-oh
Out[5]: b'\r\n'

In [6]: with open("out", "wb") as file:
   ...:     file.write(b"\n")
   ...:

In [7]: with open("out", "r") as file:
   ...:     s = file.read()
   ...:

In [8]: s  # I expect "\n" and I get it
Out[8]: '\n'

In [9]: with open("out", "rb") as file:
   ...:     b = file.read()
   ...:

In [10]: b  # I expect b"\n" and I get it
Out[10]: b'\n'

以更有组织的方式:

| Method of Writing | Method of Reading | "\n" Turns Into |
|-------------------|-------------------|-----------------|
| "w"               | "r"               | "\n"            |
| "w"               | "rb"              | b"\r\n"         |
| "wb"              | "r"               | "\n"            |
| "wb"              | "rb"              | b"\n"           |

当我在我的Linux虚拟机上尝试时,它总是返回 \n。我在Windows该怎么做?

编辑:这对于pandas库尤其成问题,它似乎使用“w”将DataFrame写入csv, 并使用“rb”读取csv。请参阅顶部链接的问题以获取示例。


1
在文本模式下,Python会将所有行结尾替换为系统默认值。使用二进制模式并自己编码字符串以使用自定义行结尾。 - Mad Physicist
1
或者,当您打开文件时指定行尾。这可能是一种更清晰的方法。 - Mad Physicist
3个回答

13
既然您正在使用Python 3,那么就很幸运了。在打开文件进行写入时,只需指定newline ='\n'即可确保它写入的是'\n'而不是系统默认的\r\n(Windows上的换行符)。来自文档的说明如下:

向流中写入输出时,如果newlineNone,则写入的任何'\n'字符都会转换为系统默认的行分隔符os.linesep。如果newline'''\n',则不会进行任何转换。如果newline是其他合法值之一,则写入的任何'\n'字符都会被转换为给定的字符串。

您认为您“有时”看到两个字符的输出的原因是,当您以二进制模式打开文件时,根本没有进行任何转换。字节数组仅在可能的情况下以ASCII方式显示,以方便您使用。在解码之前,请不要将它们视为真正的字符串。所有示例中的二进制输出都是文件的真实内容。
在默认文本模式下打开文件进行读取时,newline参数将与写入时的工作方式类似。默认情况下,在从字符解码后,文件中的所有\r\n都将转换为\n。当您的代码在操作系统之间移植而文件不移植时,这非常好,因为您可以使用仅依赖于\n的完全相同的代码。如果您的文件也要移植,则至少应将输出保持相对可移植性的newline ='\n'

4

文档中得知:

newline 控制通用换行模式的工作方式(仅适用于文本模式)。它可以是 None'''\n''\r''\r\n'。它的工作方式如下:

[...]

  • 当向流中写入输出时,如果 newlineNone,则写入的任何 '\n' 字符都将被翻译成系统默认的行分隔符 os.linesep。如果 newline'''\n',则不进行任何翻译。如果 newline 是其他合法值之一,则写入的任何 '\n' 字符都将被翻译为给定的字符串。
open(..., 'w', newline='')

0

文件的编码通常是与系统相关的。正如上面的答案所提到的,如果'\n'适用于我们,我们可以硬编码换行选项。但是当您从云中获取文件或数据时,这种方法将无法使用,因为它们经常受到限制的访问并解析为轻量级便携文件格式。因此,消除默认的二进制或任何其他编码的最佳方法是使用decode()方法和file.read()输出来处理任何编码数据。 例如,在您的情况下

In [1]: with open("out", "w") as file:
   ...:     file.write("\n")

In [q]: with open("out", "file permission") as file:
   ...:     s = file.read().decode()

#--------------------------- OR --------------------------c

In [q`]: with open(..., newline='delimiter of your choice') as file:
   ...:     s = file.read()  




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