为啥在我停止程序之前不会写入文件?

Posted

技术标签:

【中文标题】为啥在我停止程序之前不会写入文件?【英文标题】:How come a file doesn't get written until I stop the program?为什么在我停止程序之前不会写入文件? 【发布时间】:2012-04-07 03:55:18 【问题描述】:

我正在运行一个测试,发现文件实际上并没有被写入,直到我控制-C 来中止程序。谁能解释一下为什么会这样?

我希望它同时写入,所以我可以在进程中间读取文件。

import os
from time import sleep

f = open("log.txt", "a+")
i = 0
while True:
  f.write(str(i))
  f.write("\n")
  i += 1
  sleep(0.1)

【问题讨论】:

回复:“解释原因”,见***.com/questions/1450551/… 【参考方案1】:

您需要f.close() 将文件写入缓冲区刷新到文件中。或者在你的情况下,你可能只想做一个f.flush(); os.fsync();,这样你就可以继续循环打开的文件句柄。

别忘了import os

【讨论】:

确实如此,但这并不能保证在没有 os.fsync() 的情况下完全写入磁盘 不是一直到磁盘,但如果它对其他程序可见,这就是他在这里要求的。 os.fsync() 很昂贵,除非你真的知道你想要它(并且通常有办法让用户关闭它),否则不应该使用它。请注意,即使大多数数据库都有禁用 fsync 的方法——有时用户希望冒数据损坏的风险以加快速度。 真的,+1。提问者还应牢记操作系统之间的不同行为。【参考方案2】:

您需要查看file.flush() - 尽管请注意这可能不会将数据写入磁盘,引用:

注意: flush() 不一定将文件的数据写入磁盘。使用 flush() 后跟 os.fsync() 来确保这种行为。

关闭文件 (file.close()) 也将确保写入数据 - 使用 with 会隐式执行此操作,通常是提高可读性和清晰度的更好选择 - 更不用说解决其他潜在问题了。

【讨论】:

【参考方案3】:

这是一种视窗主义。如果您在处理完文件后添加显式.close(),它将在那时出现在资源管理器中。即使只是冲洗它也可能就足够了(我没有方便测试的 Windows 框)。但基本上 f.write 实际上并不写入,它只是附加到写入缓冲区 - 直到缓冲区被刷新,你才会看到它。

在 unix 上,在这种情况下文件通常会显示为 0 字节文件。

【讨论】:

【参考方案4】:

写入磁盘很慢,因此许多程序将写入存储到大块中,它们一次写入。这称为缓冲,当您打开文件时,Python 会自动执行此操作。

当您写入文件时,您实际上是在写入内存中的“缓冲区”。当它填满时,Python 会自动将其写入磁盘。您可以告诉它“现在将缓冲区中的所有内容写入磁盘”

f.flush()

这还不是全部,因为操作系统可能也会缓冲写入。您可以告诉 it

写入文件的缓冲区
os.fsync(f.fileno())

最后,您可以告诉 Python 不要使用 open(f, "w", 0) 缓冲特定文件,或者只使用 open(f,"w", 1) 保留 1 行缓冲区。当然,这会减慢对该文件的所有操作,因为写入速度很慢。

【讨论】:

请注意,免费的fsync()s 是那些关心电池寿命的带有旋转磁盘驱动器的笔记本电脑的人的祸根。您无需调用fsync() 即可让其他程序可以看到内容;它更接近于意外重启后的可见性(尽管它也不一定是充分条件)。 @CharlesDuffy:You don't need to call fsync() to get content to be visible to other programs:为什么?我认为如果你的程序没有完成,而其他程序读取该文件,它的内容可能不会更新。 @MarcoSulla, fsync() 从块缓存同步到磁盘,但块缓存也与其他程序共享。 @MarcoSulla, ...因此,只要您完成了成功的write() 系统调用——flush() 保证——该内容会被操作系统识别并生成可用于其他软件。唯一的例外是共享(网络)文件系统。 @MarcoSulla, ...我还没有看到对上述内容的任何确认——我需要查找来源/文档吗?【参考方案5】:

要刷新的文件处理程序。

f.flush()

【讨论】:

【参考方案6】:

文件不会被写入,因为在垃圾回收生效之前不会刷新输出缓冲区,并刷新 I/O 缓冲区(很可能通过调用 f.close())。

或者,在您的循环中,您可以调用f.flush(),然后调用os.fsync(),如here 所述。

f.flush()
os.fsync()

话虽如此,如果您打算与代码的其他部分共享该文件中的数据,我强烈建议您使用StringIO 对象。

【讨论】:

【参考方案7】:

你必须强制写入,所以我使用以下几行来确保写入文件:

# Two commands together force the OS to store the file buffer to disc
    f.flush()
    os.fsync(f.fileno())

【讨论】:

以上是关于为啥在我停止程序之前不会写入文件?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Windows 服务不会写入我的日志文件?

为啥在写入文件之前转移一个 int?

AVAssetWriter 停止在 iOS7 中写入文件

为啥对 NVMe SSD 上的单个文件进行并发随机写入不会导致吞吐量增加?

写入文件后,为啥 os.path.getsize 仍然返回之前的大小?

为啥向HttpServletResponse中写入相应正文之后,就无法用setHeader()方法改变响应头了。