ZetCode

Python os.fsync 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨了 Python 的 os.fsync 函数,该函数强制将写入操作刷新到磁盘。我们将介绍文件同步、性能影响和实际用例。

基本定义

os.fsync 函数强制将文件缓冲区的内容写入磁盘。它确保所有修改的数据和属性都写入永久存储。

关键参数:fd(文件描述符)。没有返回值。如果操作失败,则引发 OSError。适用于 Unix 和 Windows 系统。

基本文件同步

此示例演示了 os.fsync 的基本用法,以确保在文件操作后将数据写入磁盘。这对于关键数据完整性至关重要。

basic_sync.py
import os

# Open file for writing
file_path = "important_data.txt"
with open(file_path, "w") as f:
    # Write data to file
    f.write("Critical transaction data\n")
    f.write("Must not be lost on system crash\n")
    
    # Force write to disk
    f.flush()
    os.fsync(f.fileno())

print("Data safely written to disk")

该示例将关键数据写入文件,并确保将其物理写入磁盘。如果没有 fsync,数据可能会在崩溃期间保留在系统缓冲区中。

请注意,我们首先调用 flush() 以确保 Python 的缓冲区为空,然后调用 fsync 以强制操作系统写入磁盘。

数据库事务安全性

此示例显示了如何使用 os.fsync 来确保数据库事务的持久性。它模仿了一个简单的事务日志实现。

db_transaction.py
import os

def log_transaction(transaction_data):
    with open("transaction.log", "a") as log_file:
        log_file.write(f"Transaction: {transaction_data}\n")
        log_file.flush()
        os.fsync(log_file.fileno())
    
    print("Transaction safely logged")

# Example usage
log_transaction("UPDATE accounts SET balance=1000 WHERE id=1")
log_transaction("INSERT INTO logs VALUES ('account_update', NOW())")

每个事务都会立即写入磁盘,然后再继续。如果在事务后系统崩溃,这可以防止数据丢失。

在真实的数据库中,此技术可确保 ACID 属性,特别是持久性(ACID 中的“D”)。

性能影响测量

此示例演示了使用 os.fsync 的性能影响,通过比较有和没有同步的写入操作。

performance_test.py
import os
import time

def test_write(count, use_fsync):
    start = time.time()
    with open("testfile.txt", "w") as f:
        for i in range(count):
            f.write(f"Line {i}\n")
            if use_fsync:
                f.flush()
                os.fsync(f.fileno())
    return time.time() - start

# Test without fsync
time_no_sync = test_write(1000, False)
print(f"Without fsync: {time_no_sync:.4f} seconds")

# Test with fsync
time_with_sync = test_write(1000, True)
print(f"With fsync: {time_with_sync:.4f} seconds")

ratio = time_with_sync / time_no_sync
print(f"fsync is {ratio:.1f}x slower")

该示例在每次写入后使用和不使用 fsync 的情况下,将 1000 行写入文件。它测量并比较了执行时间。

结果将显示 fsync 由于磁盘 I/O 开销而明显较慢。谨慎地在数据完整性至关重要的地方使用它。

目录同步

此示例显示了如何使用目录文件描述符上的 os.fsync 来同步文件和目录元数据。

dir_sync.py
import os

def create_file_with_metadata_sync(filename, content):
    # Get directory path and open directory
    dir_path = os.path.dirname(filename)
    if dir_path == "":
        dir_path = "."
    
    dir_fd = os.open(dir_path, os.O_RDONLY)
    
    # Create and write file
    with open(filename, "w") as f:
        f.write(content)
        f.flush()
        os.fsync(f.fileno())  # Sync file data
    
    # Sync directory metadata
    os.fsync(dir_fd)
    os.close(dir_fd)
    
    print(f"File {filename} created with full metadata sync")

create_file_with_metadata_sync("new_config.cfg", "[settings]\noption=value\n")

该示例确保文件数据和目录元数据都已同步到磁盘。当文件存在至关重要时,这很重要。

目录同步确保新文件的元数据是持久的,而不仅仅是文件内容。

原子文件替换

此示例演示了一种原子文件替换模式,使用 os.fsync 确保操作期间的数据完整性。

atomic_replace.py
import os

def atomic_replace(filename, content):
    # Write to temporary file
    tempname = filename + ".tmp"
    with open(tempname, "w") as f:
        f.write(content)
        f.flush()
        os.fsync(f.fileno())
    
    # Replace original file
    os.replace(tempname, filename)
    
    # Sync directory
    dir_fd = os.open(os.path.dirname(filename) or ".", os.O_RDONLY)
    os.fsync(dir_fd)
    os.close(dir_fd)
    
    print(f"Atomically replaced {filename}")

atomic_replace("config.json", '{"version": 2, "settings": {"debug": false}}')

该示例首先写入临时文件,将其同步到磁盘,然后执行原子重命名操作。最后,它同步目录元数据。

此模式确保原始文件要么完全保留,要么完全替换,而永远不会处于部分更新状态。

跨平台注意事项

此示例演示了如何处理 Unix 和 Windows 系统之间 os.fsync 的差异,包括错误处理。

cross_platform.py
import os
import sys

def safe_sync(file_obj):
    try:
        file_obj.flush()
        os.fsync(file_obj.fileno())
    except AttributeError:
        # On Windows, sometimes need to call _commit
        if sys.platform == "win32":
            import msvcrt
            msvcrt._commit(file_obj.fileno())
        else:
            raise

def write_with_sync(filename, data):
    with open(filename, "w") as f:
        f.write(data)
        safe_sync(f)
    print(f"Data safely written to {filename}")

write_with_sync("data.bin", b"\x00\x01\x02\x03\x04")

该示例提供了一个跨平台同步函数,该函数通过 msvcrt 模块处理 Windows 特定的需求。

在 Windows 上,可能需要在某些情况下使用 _commit 来确保数据写入磁盘,类似于 Unix 系统上的 fsync。

错误处理

此示例演示了使用 os.fsync 时的正确错误处理,包括同步可能失败的情况。

error_handling.py
import os
import errno

def write_with_guarantee(filename, data):
    try:
        with open(filename, "w") as f:
            f.write(data)
            f.flush()
            try:
                os.fsync(f.fileno())
                print("Data successfully synchronized to disk")
            except OSError as e:
                if e.errno == errno.EINVAL:
                    print("Warning: fsync not supported on this filesystem")
                else:
                    raise
    except IOError as e:
        print(f"Failed to write file: {e}")

write_with_guarantee("critical.log", "System shutdown initiated\n")

该示例处理了文件写入和同步期间可能发生的各种错误情况,包括不支持的操作。

EINVAL 错误专门处理文件系统不支持同步的情况,这在某些网络文件系统中很常见。

安全注意事项

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程