ChatGPT解决这个技术问题 Extra ChatGPT

将行写入文件的正确方法?

如何在现代 Python 中将一行写入文件?我听说这已被弃用:

print >>f, "hi there"

此外,"\n" 是否适用于所有平台,还是我应该在 Windows 上使用 "\r\n"

"\n" 不是 Unix 特定的。当文件以文本模式(默认)打开时,它会自动转换为当前平台的正确行尾。写 "\r\n" 会产生 "\r\r\n" 这是错误的。
只需添加 print ord(os.linesep) 语句即可查看 ascii 代码(大多数 UNIX 系统上为 10)
为什么你认为它已被弃用?

u
user35443

这应该很简单:

with open('somefile.txt', 'a') as the_file:
    the_file.write('Hello\n')

从文档:

写入以文本模式打开的文件时,不要使用 os.linesep 作为行终止符(默认);在所有平台上使用单个 '\n'。

一些有用的阅读:

with 语句

open() 'a' 用于追加,或使用 'w' 进行截断

'a' 用于附加或使用

'w' 用截断写

操作系统(尤其是 os.linesep)


此示例优于打开/关闭示例。使用 with 是记住关闭文件的一种更安全的方法。
我不必打电话给 the_file.close() 吗?
@HorseSMith:我明白了。希望我最近的编辑能澄清我的意图。如果它们“相当无用且具有误导性”,请随时编辑我的答案。
@user3226167:这是一个有趣的观点。但是你为什么要打开一个二进制文件来写纯文本呢?
M
Martin Tournoij

您应该使用自 Python 2.6+ 起可用的 print() 函数

from __future__ import print_function  # Only needed for Python 2
print("hi there", file=f)

对于 Python 3,您不需要 import,因为 print() 函数是默认值。

另一种方法是使用:

f = open('myfile', 'w')
f.write('hi there\n')  # python will convert \n to os.linesep
f.close()  # you can omit in most cases as the destructor will call it

引用 Python documentation 关于换行符:

在输出时,如果换行符为 None,则写入的任何 '\n' 字符都将转换为系统默认行分隔符 os.linesep。如果换行符是 '',则不进行翻译。如果换行符是任何其他合法值,则写入的任何 '\n' 字符都将转换为给定的字符串。


-1 “如果你想确定,将 os.linesep 添加到字符串而不是 \n”将需要 newline="" 否则你会在 Windows 上得到 \r\r\n。根本没有理由对 os.linesep 大发雷霆。
@Sorin:您添加写入模式的编辑当然是一种改进。然而,奇怪的是,你对 os.linesep 仍然顽固不化。看我的回答。顺便说一句,您引用的文档适用于 3.x,但这部分在文本模式下也适用于 2.x:任何写入的 '\n' 字符都将转换为系统默认的行分隔符 os。 linesep* ... Windows:编写 os.linesep 与编写包含 \n\r\n 相同,\n 被转换为 os.linesep,即 \r\n,因此最终结果为 \r\r\n
@John 你是对的,我纠正了 os.linesep 错误。谢谢。
追加不是 open('myfile','a') 而不是 open('myfile','w')
@BradRuderman 这是构成文本文件中“行”的 POSIX 标准的一部分,即文本文件中的每一行都必须以换行符终止,即使是最后一行。
d
dcoles

python docs 推荐这种方式:

with open('file_to_write', 'w') as f:
    f.write('file contents\n')

所以这是我通常这样做的方式:)

docs.python.org 的声明:

在处理文件对象时,最好使用“with”关键字。这样做的好处是文件在其套件完成后正确关闭,即使在途中引发异常也是如此。它也比编写等效的 try-finally 块要短得多。


当我需要将 with 嵌套在循环中时,我不喜欢这种方式。这使我在循环中继续打开和关闭文件。也许我在这里遗漏了一些东西,或者这在这种特殊情况下真的是一个缺点?
在 with 中循环怎么样?
@j7nn7k 用于 fd 中的行:
J
John Machin

关于 os.linesep:

这是 Windows 上一个完全未经编辑的 Python 2.7.1 解释器会话:

Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.linesep
'\r\n'
>>> f = open('myfile','w')
>>> f.write('hi there\n')
>>> f.write('hi there' + os.linesep) # same result as previous line ?????????
>>> f.close()
>>> open('myfile', 'rb').read()
'hi there\r\nhi there\r\r\n'
>>>

在 Windows 上:

正如预期的那样,os.linesep NOT 产生与 '\n' 相同的结果。它不可能产生相同的结果。 'hi there' + os.linesep 等同于 'hi there\r\n',而 NOT 等同于 'hi there\n'

就这么简单:使用 \n,它会自动转换为 os.linesep。 自从 Python 首次移植到 Windows 以来,它就是这么简单。

在非 Windows 系统上使用 os.linesep 是没有意义的,它在 Windows 上会产生错误的结果。

不要使用 os.linesep!


很好的例子——好奇你是不是 ipython 用户?格式化会话的好功能
我不完全确定你想在这里告诉我们什么。 os.linesep 将返回操作系统定义的行术语字符(或字符串)。 Windows 默认使用 \r\n 作为行尾。但是,单个 \n 被识别。使用 \n 将提供完全可移植的 OUTPUT 但 os.linesep 在 Windows 上并没有错。
@Gusdor:关键是如果您在 Windows 中以文本模式显式使用 os.linesep,则结果是 \r\r\n 这是错误的。 “Windows 使用...”毫无意义。 C 运行时库(以及 Python)在文本模式下的输出中将 \n 转换为 \r\n。其他软件的行为可能不同。在以文本模式阅读时,并非所有在 Windows 上运行的软件都将单独的 \n 识别为行分隔符。 Python 可以。微软的记事本文本编辑器没有。
可以说,其他人会阅读它,而不是你,使用一些米老鼠软件会吐出额外的 \r ...
@Gusdor 你是从另一种语言来到 python 的吗,使用 '\n' 会在窗口上输出 '\n' 而不是 '\r\n' - 所以它缺少哑巴所期望的 '\r'文本编辑器?正如 John 所说,这不是 Python 的行为方式——'\n' 会自动替换为 '\r\n',如果这是 os.linesep 所说的那样。因此,在这里明确地说 os.linesep is “错误”。它就像 Department of Redundancy Department。是的,你可以做到。不,你不想。
H
Hyperboreus

我认为没有“正确”的方式。

我会使用:

with open ('myfile', 'a') as f: f.write ('hi there\n')

谨记Tim Toady


但是 OP 可能想要在文件中写入额外的东西。当 with 超出范围时,文件将在此处关闭。
嗯,是的。这就是使用 with 的想法。如果要保持文件打开,只需在开始时调用 open 并在完成后调用 close ...
@mtrw。真的。 OP正在附加。
就 python 而言,RIP Tim Toady - 非常非常非常正确
zen of perl 有点矛盾。
K
Keith

在 Python 3 中它是一个函数,但在 Python 2 中,您可以将其添加到源文件的顶部:

from __future__ import print_function

然后你做

print("hi there", file=f)

R
Robin Keskisarkka

如果您正在写入大量数据并且速度是一个问题,您可能应该使用 f.write(...)。我做了一个快速的速度比较,在执行大量写入时它比 print(..., file=f) 快得多。

import time    

start = start = time.time()
with open("test.txt", 'w') as f:
    for i in range(10000000):
        # print('This is a speed test', file=f)
        # f.write('This is a speed test\n')
end = time.time()
print(end - start)

在我的机器上,write 平均在 2.45 秒内完成,而 print 大约需要 4 倍的时间(9.76 秒)。话虽如此,在大多数现实世界的场景中,这都不是问题。

如果您选择使用 print(..., file=f),您可能会发现您需要不时取消换行符,或者用其他内容替换它。这可以通过设置可选的 end 参数来完成,例如;

with open("test", 'w') as f:
    print('Foo1,', file=f, end='')
    print('Foo2,', file=f, end='')
    print('Foo3', file=f)

无论您选择哪种方式,我都建议您使用 with,因为它使代码更易于阅读。

更新:这种性能差异的原因是 write 被高度缓冲并在实际写入磁盘之前返回(请参阅 this answer),而 print(可能)使用行缓冲。对此的一个简单测试是检查长写入的性能,其中行缓冲的缺点(在速度方面)将不那么明显。

start = start = time.time()
long_line = 'This is a speed test' * 100
with open("test.txt", 'w') as f:
    for i in range(1000000):
        # print(long_line, file=f)
        # f.write(long_line + '\n')
end = time.time()

print(end - start, "s")

现在,性能差异变得不那么明显了,write 的平均时间为 2.20 秒,print 的平均时间为 3.10 秒。如果您需要连接一堆字符串来获得这种长线性能将会受到影响,因此 print 更有效的用例有点少见。


无需为每一行多次调用 print(),您可以输入每一行作为位置参数并使用 print(line1, line2, ... sep="\n") 指定换行符。这只会进行一次写入调用。
C
Community

从 3.5 开始,您还可以为此目的使用 pathlib

Path.write_text(data, encoding=None, errors=None) 以文本模式打开指向的文件,写入数据,然后关闭文件:

import pathlib

pathlib.Path('textfile.txt').write_text('content')

a
alper

当您说 Line 时,它表示一些以 '\n' 字符结尾的序列化字符。行应该在某个点最后,所以我们应该在每行的末尾考虑 '\n'。这是解决方案:

with open('YOURFILE.txt', 'a') as the_file:
    the_file.write("Hello")

在每次写入后的追加模式下,光标移动到新行,如果你想使用 w 模式,你应该在 write() 函数的末尾添加 \n 字符:

the_file.write("Hello\n")

“在每次写入后以追加模式移动光标到新行”——不,不是。
k
kmario23

也可以使用 io 模块,如下所示:

import io
my_string = "hi there"

with io.open("output_file.txt", mode='w', encoding='utf-8') as f:
    f.write(my_string)

Z
Zenul_Abidin

如果您想避免使用 write()writelines() 并自己用换行符连接字符串,您可以将所有行传递给 print(),并将换行符分隔符和文件句柄作为关键字参数传递。此代码段假定您的字符串没有尾随换行符。

print(line1, line2, sep="\n", file=f)

您不需要在末尾添加特殊的换行符,因为 print() 会为您完成。

如果列表中有任意数量的行,则可以使用列表扩展将它们全部传递给 print()

lines = ["The Quick Brown Fox", "Lorem Ipsum"]
print(*lines, sep="\n", file=f)

在 Windows 上使用 "\n" 作为分隔符是可以的,因为 print() 还会自动将其转换为 Windows CRLF 换行符 ("\r\n")。


H
Higgs

如果您想以每行的格式在列表中插入项目,开始的方法可能是:

with open('somefile.txt', 'a') as the_file:
    for item in items:
        the_file.write(f"{item}\n")

S
Sashini Hettiarachchi

要在烧瓶中的文件中写入文本,可以使用:

filehandle = open("text.txt", "w")
filebuffer = ["hi","welcome","yes yes welcome"]
filehandle.writelines(filebuffer)
filehandle.close()

始终建议使用 with open('file_to_write', 'w') as f: 语句写入文件。如果有人不小心在两者之间写了一些东西会导致没有明确的 close() 调用,那么确保文件不会保持打开状态要容易得多
E
Emin Bugra Saral

您也可以尝试filewriter

pip install filewriter

from filewriter import Writer

Writer(filename='my_file', ext='txt') << ["row 1 hi there", "row 2"]

写入 my_file.txt

采用支持 __str__ 的可迭代对象或对象。


M
MxNx

当我需要编写很多新行时,我定义了一个使用 print 函数的 lambda:

out = open(file_name, 'w')
fwl = lambda *x, **y: print(*x, **y, file=out) # FileWriteLine
fwl('Hi')

这种方法的好处是它可以利用 print 函数提供的所有功能。

更新: 正如评论部分中 Georgy 所提到的,可以使用 partial 函数进一步改进这个想法:

from functools import partial
fwl = partial(print, file=out)

恕我直言,这是一种更实用、更不神秘的方法。


或者另一种(可能更简洁)的写法:from functools import partial; fwl = partial(print, file=out)
@Georgy您的方法非常好,可以作为新答案给出。
这个想法和你的一样,只是实现有点不同。如果需要,您可以将其添加到答案的编辑中。我很好。
A
Abhishek Kumar

将python中的行写入文本文件的一种非常基本的方法。如果存在,这将覆盖具有相同名称的文件。

%%writefile test.txt
 i am writing this to test.txt file \n
 writing this line also

这仅适用于 Jupyter 或 ipython,因为“普通”python 解释器无法识别魔法。请调整您的答案以指定
H
Hyperx837

由于其他人已经回答了如何做到这一点,我将逐行回答它是如何发生的。

with FileOpenerCM('file.txt') as fp: # is equal to "with open('file.txt') as fp:"
      fp.write('dummy text')

这就是所谓的 context manager,任何带有 with 块的东西都是上下文管理器。所以让我们看看这在幕后是如何发生的。

class FileOpenerCM:
     def __init__(self, file, mode='w'):
         self.file = open(file, mode)
      
     def __enter__(self):
          return self.file
      
     def __exit__(self, exc_type, exc_value, exc_traceback):
         self.file.close()

第一个方法 __init__ 是(众所周知)对象的初始化方法。每当创建对象时,肯定会调用 obj.__init__。这就是你放置所有初始化代码的地方。

第二种方法__enter__有点意思。你们中的一些人可能没有看到它,因为它是上下文管理器的特定方法。它返回的是在 as 关键字之后分配给变量的值。在我们的例子中,fp

最后一种方法是在捕获错误或代码退出 with 块后运行的方法。 exc_typeexc_valueexc_traceback 变量是保存 with 块内部发生的错误值的变量。例如,

exc_type: TypeError
exc_value: unsupported operand type(s) for +: 'int' and 'str
exc_traceback: <traceback object at 0x6af8ee10bc4d>

从前两个变量中,您可以获得有关错误的足够信息。老实说,我不知道第三个变量的用途,但对我来说,前两个就足够了。如果您想对上下文管理器进行更多研究,那么您肯定可以做到,并注意编写类并不是编写上下文管理器的唯一方法。使用 contextlib,您也可以通过函数(实际上是生成器)编写上下文管理器。完全由你来看看它。您当然可以尝试使用 contextlib 生成器函数,但正如我所见,类更干净。