用Python原子写入文件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Python原子写入文件相关的知识,希望对你有一定的参考价值。
我使用Python在一个操作中将文本块写入文件:
open(file, 'w').write(text)
如果脚本被中断,那么文件写入没有完成我想要没有文件而不是部分完整的文件。可以这样做吗?
将数据写入临时文件,并且在成功写入数据后,将文件重命名为正确的目标文件,例如
f = open(tmpFile, 'w')
f.write(text)
# make sure that all data is on disk
# see http://stackoverflow.com/questions/7433057/is-rename-without-fsync-safe
f.flush()
os.fsync(f.fileno())
f.close()
os.rename(tmpFile, myFile)
据http://docs.python.org/library/os.html#os.rename博士说
如果成功,重命名将是原子操作(这是POSIX要求)。在Windows上,如果dst已经存在,即使它是文件,也会引发OSError;当dst命名现有文件时,可能无法实现原子重命名
也
如果src和dst在不同的文件系统上,则某些Unix风格的操作可能会失败。
注意:
- 如果src和dest位置不在同一文件系统上,则可能不是原子操作
- 如果性能/响应性比电源故障,系统崩溃等情况下的数据完整性更重要,则可以跳过
os.fsync
步骤
一个简单的片段,使用Python tempfile
实现原子写作。
with open_atomic('test.txt', 'w') as f:
f.write("huzza")
甚至可以在同一个文件中读写:
with open('test.txt', 'r') as src:
with open_atomic('test.txt', 'w') as dst:
for line in src:
dst.write(line)
使用两个简单的上下文管理
import os
import tempfile as tmp
from contextlib import contextmanager
@contextmanager
def tempfile(suffix='', dir=None):
""" Context for temporary file.
Will find a free temporary filename upon entering
and will try to delete the file on leaving, even in case of an exception.
Parameters
----------
suffix : string
optional file suffix
dir : string
optional directory to save temporary file in
"""
tf = tmp.NamedTemporaryFile(delete=False, suffix=suffix, dir=dir)
tf.file.close()
try:
yield tf.name
finally:
try:
os.remove(tf.name)
except OSError as e:
if e.errno == 2:
pass
else:
raise
@contextmanager
def open_atomic(filepath, *args, **kwargs):
""" Open temporary file object that atomically moves to destination upon
exiting.
Allows reading and writing to and from the same filename.
The file will not be moved to destination in case of an exception.
Parameters
----------
filepath : string
the file path to be opened
fsync : bool
whether to force write the file to disk
*args : mixed
Any valid arguments for :code:`open`
**kwargs : mixed
Any valid keyword arguments for :code:`open`
"""
fsync = kwargs.get('fsync', False)
with tempfile(dir=os.path.dirname(os.path.abspath(filepath))) as tmppath:
with open(tmppath, *args, **kwargs) as file:
try:
yield file
finally:
if fsync:
file.flush()
os.fsync(file.fileno())
os.rename(tmppath, filepath)
有一个简单的AtomicFile帮助器:https://github.com/sashka/atomicfile
我正在使用此代码以原子方式替换/写入文件:
import os
from contextlib import contextmanager
@contextmanager
def atomic_write(filepath, binary=False, fsync=False):
""" Writeable file object that atomically updates a file (using a temporary file).
:param filepath: the file path to be opened
:param binary: whether to open the file in a binary mode instead of textual
:param fsync: whether to force write the file to disk
"""
tmppath = filepath + '~'
while os.path.isfile(tmppath):
tmppath += '~'
try:
with open(tmppath, 'wb' if binary else 'w') as file:
yield file
if fsync:
file.flush()
os.fsync(file.fileno())
os.rename(tmppath, filepath)
finally:
try:
os.remove(tmppath)
except (IOError, OSError):
pass
用法:
with atomic_write('path/to/file') as f:
f.write("allons-y!
")
它基于this recipe。
由于很容易弄乱细节,我建议使用一个小型库。图书馆的优势在于它会照顾所有这些细节,并由社区成为reviewed and improved。
一个这样的库是python-atomicwrites
by untitaker,甚至有适当的Windows支持:
来自README:
from atomicwrites import atomic_write
with atomic_write('foo.txt', overwrite=True) as f:
f.write('Hello world.')
# "foo.txt" doesn't exist yet.
# Now it does.
用于Windows的原子解决方案循环文件夹和重命名文件。经过测试,原子自动化,您可以增加概率,以最大限度地降低风险,而不是具有相同文件名的事件。随机库中的字母符号组合使用random.choice方法,用于数字str(random.random.range(50,999999999,2)。您可以根据需要改变数字范围。
import os import random
path = "C:\Users\ANTRAS\Desktop\NUOTRAUKA\"
def renamefiles():
files = os.listdir(path)
i = 1
for file in files:
os.rename(os.path.join(path, file), os.path.join(path,
random.choice('ABCDEFGHIJKL') + str(i) + str(random.randrange(31,9999999,2)) + '.jpg'))
i = i+1
for x in range(30):
renamefiles()
以上是关于用Python原子写入文件的主要内容,如果未能解决你的问题,请参考以下文章