为什么每次我们要追加文件时都需要打开文件

  • 本文关键字:文件 追加 我们 python
  • 更新时间 :
  • 英文 :


作为线程如何附加到文件?,大多数答案是关于打开一个文件并附加到它,例如:

def FileSave(content):
with open(filename, "a") as myfile:
myfile.write(content)
FileSave("test1 n")
FileSave("test2 n")

为什么我们不提取myfile,只在调用FileSave时写入它呢。

global myfile
myfile = open(filename)
def FileSave(content):
myfile.write(content)
FileSave("test1 n")
FileSave("test2 n")

后一种代码更好吗?因为它只打开一次文件并多次写入?或者,没有区别,因为python内部的内容将保证文件只打开一次,尽管open方法被调用了多次。

修改后的代码有很多问题与您的问题无关:您以只读模式打开文件,从不关闭文件,您有一个global语句什么都不做…

让我们忽略所有这些,只讨论一遍又一遍地打开和关闭文件的优点和缺点:

  • 浪费一点时间。如果你真的很不走运,文件甚至可能会一直从磁盘缓存中掉出来,浪费更多的时间
  • 确保您总是附加到文件的末尾,即使其他程序也附加到同一个文件。(这对于例如syslog类型的日志非常重要。)1
  • 确保您已在某个时刻将写操作刷新到磁盘,这样可以减少程序崩溃或终止时数据丢失的几率
  • 确保写入后立即将写入刷新到磁盘。如果你试图在同一程序或不同程序的其他地方打开和读取文件,或者最终用户只是在记事本中打开它,你不会错过最后1.73KB的行,因为它们仍然在某个缓冲区中,直到稍后才会写入2

所以,这是一种权衡。通常,您想要其中一种保证,而性能成本并不是什么大不了的事。有时候,这是一件大事,保证并不重要。有时,你真的需要两者,所以你必须写一些复杂的东西,手动缓冲比特,一次写入并刷新所有比特。


1。正如open的Python文档所表明的,这无论如何都会在一些Unix系统上发生。但不是在其他Unix系统上,也不是在Windows上

2.此外,如果有多个写入程序,它们一次都会追加一行,而不是在每次刷新时都追加,这对日志文件来说同样非常重要

如果可能,一般应避免global

人们在处理文件时使用with命令的原因是它明确控制了作用域。一旦with运算符完成,则关闭文件并丢弃文件变量。

您可以避免使用with运算符,但必须记住调用myfile.close()。尤其是在处理大量文件的情况下。

避免使用with块的一种方法也是避免使用全局的

def filesave(f_obj, string):
f_obj.write(string)
f = open(filename, 'a')
filesave(f, "test1n")
filesave(f, "test2n")
f.close()

然而,在这一点上,你最好去掉这个功能,简单地做:

f = open(filename, 'a')
f.write("test1n")
f.write("test2n")
f.close()

在这一点上,你可以很容易地将它放在with块中:

with open(filename, 'a') as f:
f.write("test1n")
f.write("test2n")

是的。没有任何理由不去做你正在做的事情。这不太像Python。

后一种代码可能更高效,但前一种代码更安全,因为它确保每次对FileSave的调用写入文件的内容都被刷新到文件系统,以便其他进程可以读取更新的内容,并通过使用open作为上下文管理器关闭每次调用的文件句柄,您允许其他进程也有机会写入该文件(特别是在Windows中)。

这确实取决于具体情况,但这里有一些想法:

with块绝对保证一旦退出该块,文件将被关闭。Python不会对附加文件进行奇怪的优化。

一般来说,全局变量会降低代码的模块化程度,因此更难读取和维护。您可能会认为最初的FileSave函数试图避免使用全局文件,但它使用的是全局名称filename,因此此时您还可以完全使用一个全局文件,因为这将节省一些I/O开销。

一个更好的选择是完全避免全局变量,或者至少正确使用它们。你真的不需要一个单独的函数来包装file.write,但如果它代表了更复杂的东西,这里有一个设计建议:

def save(file, content):
print(content, file=file)
def my_thing(filename):
with open(filename, 'a') as f:
# do some stuff
save(f, 'test1')
# do more stuff
save(f, 'test2')
if __name__ == '__main__':
my_thing('myfile.txt')

请注意,当您将模块作为脚本调用时,在全局范围中定义的文件名将传递给主例程。然而,由于主例程不引用全局变量,您可以A)更容易地读取它,因为它是自包含的,B)测试它,而不必考虑如何在不破坏其他一切的情况下为它提供输入。

此外,通过使用print而不是file.write,可以避免手动花费换行符。

最新更新