繁体   English   中英

os.link() 与 os.rename() 与 os.replace() 用于编写原子写入文件。 最好的方法是什么?

[英]os.link() vs. os.rename() vs. os.replace() for writing atomic write files. What is the best approach?

嗨,我正在尝试编写一个像这样的原子写入函数......

with tempfile.NamedTemporaryFile(mode= "w", dir= target_directory) as f: 
     #perform file writing operation  
     os.replace(f.name, target_file_name) 

我正在努力弄清楚在第 3 行中执行的最佳操作是什么。我应该使用 os.replace()、os.rename() 还是应该使用 os.link() 在临时文件和目标文件之间创建硬链接?

os.link() 使用更多内存吗? 每个的好处是什么,它们都是原子的?

嗨,我正在尝试编写一个原子写函数,如下所示:

with tempfile.NamedTemporaryFile(mode= "w", dir= target_directory) as f: 
     #perform file writing operation  
     os.replace(f.name, target_file_name) 

我正在努力找出在第3行中最好的操作是什么?我应该使用os.replace(),os.rename()还是应该使用os.link()在tempfile和目标文件之间创建硬链接?

os.link()是否使用更多的内存? 每个都有什么好处,并且都是原子性的?

嗨,我正在尝试编写一个原子写函数,如下所示:

with tempfile.NamedTemporaryFile(mode= "w", dir= target_directory) as f: 
     #perform file writing operation  
     os.replace(f.name, target_file_name) 

我正在努力找出在第3行中最好的操作是什么?我应该使用os.replace(),os.rename()还是应该使用os.link()在tempfile和目标文件之间创建硬链接?

os.link()是否使用更多的内存? 每个都有什么好处,并且都是原子性的?

首先, os.link创建硬链接,这意味着 src-link 与 dst-link 共享相同的空间。 不执行复制-写入操作 - 因此没有内存开销。 遗憾的是,硬链接并非与所有文件系统兼容。 例如,NTFS 支持硬链接,而 FAT 和 ReFS 不支持。

其次os.replace应该优先于os.rename因为它更平台(仅适用于 Python 3.3+)。 另一个重要的事情是源路径和目标路径必须在同一个物理磁盘上。 至于原子性,在 Unix\\Windows 上的所有可能情况下, os.replace似乎很有可能(但不是 100%)是原子的。 相关链接123 无论如何,这是避免竞争条件/TOCTOU-bags的推荐方法 至于我,我从未遇到或无法重现调用os.replace最终导致 src 或 dst 数据损坏的情况。 但是,只要官方文档中没有要求这种行为, os.replace 就不应该被视为原子调用(尤其是对于 Windows)

根据定义,您的示例代码绝对不是原子的 - 在任何时候,任何相关进程都可能破坏临时文件的数据完整性; 在非 Windows 系统上突然关闭执行过程甚至可以将您的临时文件永远留在指定目录中。 为了解决这些问题,您可能需要一些同步原语、锁,而您的代码逻辑必须假设最不可能发生的数据中断或损坏情况。

这是一个常见情况的示例,当某些数据应从现有文件中提取或以其他方式在此类文件中创建时:

import time
filename = 'data' # file with data
temp_filename = 'data.temp' # temp used to create 'data'

def get_data():
    while True:
        try:
            os.remove(temp_filename)
        except FileNotFoundError: # if no data.temp
            try: # check if data already exists:
                with open(filename, 'rt', encoding='utf8') as f:
                    return f.read() # return data here
            except FileNotFoundError:
                pass # create data
        except PermissionError: # if another process/thread is creating data.temp right now
            time.sleep(0.1) # wait for it
            continue
        else:
            pass # something went wrong and it's better to create all again

        # data creation:
        excl_access = 'xt' # raises error if file exists - used as a primitive lock
        try:
            with open(temp_filename, excl_access, encoding='utf8') as f:
                # process can be interrupted here 
                f.write('Hello ') # or here
                f.write('world!') # or here
        except FileExistsError: # another one is creating it now
            time.sleep(0.1) # wait for it
            continue
        except Exception: # something went wrong
            continue
        try:
            os.replace(temp_filename, filename) # not sure this would be atomic in 100%
        except FileNotFoundError:
            continue # try again

这是一个相关的问题,其中有一些答案建议使用一些外部库来处理原子文件创建

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM