close()暗示Python中的flush()?

时间:2010-03-15 12:48:52

标签: python operating-system flush

在Python中,一般而言 - 文件对象上的close()操作是否意味着flush()操作?

5 个答案:

答案 0 :(得分:30)

是。它使用基础close()函数为您执行此操作(source)。

答案 1 :(得分:16)

注意:close()flush()无法确保数据在磁盘上实际上是安全的。它只是确保操作系统具有数据==,它不会在进程内缓冲。

您可以尝试使用sync或fsync将数据写入磁盘。

答案 2 :(得分:0)

是的,在Python 3中最终是in the official documentation,但在Python 2中已经是这种情况(请参见Martin's answer)。

答案 3 :(得分:0)

作为对这个问题的补充,是的,python 在关闭之前刷新,但是如果您想确保数据正确写入磁盘,这还不够。

这就是我在 UNIX/Linux 服务器上以原子更新的方式编写文件的方式,无论目标文件是否存在。请注意,某些文件系统会在 close+rename 时隐式提交数据到磁盘(ext3 带有 data=ordered(默认),并且 ext4 在添加检测之前最初发现了许多应用程序缺陷写入关闭重命名模式并在元数据之前同步数据[1])。

# Write destfile, using a temporary name .<name>_XXXXXXXX
base, name = os.path.split(destfile)
tmpname = os.path.join(base, '.{}_'.format(name))  # This is the tmpfile prefix
with tempfile.NamedTemporaryFile('w', prefix=tmpname, delete=False) as fd:
    # Replace prefix with actual file path/name
    tmpname = str(fd.name)

    try:
        # Write fd here... ex:
        json.dumps({}, fd)

        # We want to fdatasync before closing, so we need to flush before close anyway
        fd.flush()
        os.fdatasync(fd)

        # Since we're using tmpfile, we need to also set the proper permissions
        if os.path.exists(destfile):
            # Copy destination file's mask
            os.fchmod(fd.fileno, os.stat(destfile).st_mode)
        else:
            # Set mask based on current umask value
            umask = os.umask(0o22)
            os.umask(umask)
            os.fchmod(fd.fileno, 0o666 & ~umask)  # 0o777 for dirs and executable files)

        # Now we can close and rename the file (overwriting any existing one)
        fd.close()
        os.rename(tmpname, destfile)
    except:
        # On error, try to cleanup the temporary file
        try:
            os.unlink(tmpname)
        except OSError:
            pass
        raise

恕我直言,如果 Python 提供了一些简单的方法,那就太好了……同时,我想如果您关心数据一致性,那么最好真正了解底层发生的事情,尤其是因为有各种操作系统和文件系统之间的许多差异。

另请注意,这并不能保证写入的数据可以恢复,只是您将获得一致的数据副本(旧的或新的)。为确保新数据在返回时安全写入和访问,您需要在重命名后使用 os.fsync(...),即使这样,如果写入路径中有不安全的缓存,您仍然可能会丢失数据。这在消费级硬件上很常见,尽管任何系统都可以配置为不安全的写入,这也可以提高性能。至少即使有不安全的缓存,上述方法仍应保证您获得的数据副本是有效的。

答案 4 :(得分:-6)

filehandle.close不一定要刷新。令人惊讶的是,filehandle.flush也无济于事 - 当Python运行时它仍然会卡在OS缓冲区中。观察此会话,我写入文件,关闭它并按Ctrl-Z到shell命令提示符并检查文件:

$  cat xyz
ghi
$ fg
python

>>> x=open("xyz","a")
>>> x.write("morestuff\n")
>>> x.write("morestuff\n")
>>> x.write("morestuff\n")
>>> x.flush
<built-in method flush of file object at 0x7f58e0044660>
>>> x.close
<built-in method close of file object at 0x7f58e0044660>
>>> 
[1]+  Stopped                 python
$ cat xyz
ghi

随后我可以重新打开文件,这必然会同步文件(因为,在这种情况下,我在追加模式下打开它)。正如其他人所说的那样,sync syscall(可从os包中获得)应该将所有缓冲区刷新到磁盘,但它可能会影响整个系统的性能(它会同步系统上的所有文件)。