[英]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%)是原子的。 相關鏈接1 , 2 , 3 。 無論如何,這是避免競爭條件/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.