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

如何在现代Python中向文件写入一行?我听说这是不建议使用的:

print >>f, "hi there"

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

2577688 次浏览

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

我会使用:

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

纪念Tim Toady

您应该使用从Python 2.6+开始可用的#0函数

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

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

Python 3中的替代方案是使用:

with open('myfile', 'w') as f:f.write('hi there\n')  # python will convert \n to os.linesep

引用python留档关于换行符:

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

另见:读取和写入文件-Python教程

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

from __future__ import print_function

那你就做吧

print("hi there", file=f)

这应该像这样简单:

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

来自文档:

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

一些有用的阅读:

关于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)] onwin32Type "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不是产生与'\n'相同的结果。它不可能产生相同的结果。'hi there' + os.linesep相当于'hi there\r\n'不是相当于'hi there\n'

很简单:使用#0,它将自动翻译为os.linesep.自从Python第一次移植到Windows以来,它一直很简单。

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

不要使用os.linesep!

python文档推荐这种方式:

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

这就是我通常的做法:)

来自docs.python.org的声明:

处理文件时使用关键字是很好的做法对象。这的优点是文件在之后被正确关闭它的套件完成,即使在途中引发异常。它是也比编写等效的try-最终块短得多。

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

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

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

the_file.write("Hello\n")

如果您正在写入大量数据并且速度是一个问题,您可能应该使用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.45s,而print花费了大约4倍的时间(9.76s)。也就是说,在大多数现实世界的场景中,这不会是一个问题。

如果您选择使用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是高度缓冲的,并在任何对磁盘的写入实际发生之前返回(参见这个答案),而print(可能)使用行缓冲。对此的一个简单测试是也检查长写入的性能,其中行缓冲的缺点(在速度方面)不太明显。

start = start = time.time()long_line = 'This is a speed test' * 100with 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.20s,print的平均时间为3.10s。如果你需要连接一堆字符串来获得这种长线性能会受到影响,所以print更高效的用例有点罕见。

也可以使用io模块,如:

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

从3.5开始,您也可以为此目的使用#0

Path.write_text(data, encoding=None, errors=None)

打开以文本模式指向的文件,向其写入数据,然后关闭文件:

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

你也可以试试filewriter

pip install filewriter

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

写入my_file.txt

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

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

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

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

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

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

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

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

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

如果您想避免使用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")。

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

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变量是保存块内部发生的错误值的变量。例如,

exc_type: TypeErrorexc_value: unsupported operand type(s) for +: 'int' and 'strexc_traceback: <traceback object at 0x6af8ee10bc4d>

从前两个变量,你可以得到足够的信息关于错误.老实说,我不知道第三个变量的使用,但对我来说,前两个就足够了.如果你想做更多的研究上下文管理器当然你可以做到,并注意到编写类不是编写上下文管理器的唯一方法.使用Contextlib,你可以通过函数(实际上是生成器)编写上下文管理器.这完全取决于你来看看它.你一定可以尝试使用Contextlib的生成器函数,但我看到类更干净。

如果您想在每行格式的列表中插入项目,可以这样开始:

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