Bas*_*asj 9 python filesystems io file-io file
如如何在 Python 中复制文件?,有很多文件复制功能:
shutil.copy
shutil.copy2
shutil.copyfile(还有shutil.copyfileobj)
甚至是一种天真的方法:
with open('sourcefile', 'rb') as f, open('destfile', 'wb') as g:
while True:
block = f.read(16*1024*1024) # work by blocks of 16 MB
if not block: # EOF
break
g.write(block)
Run Code Online (Sandbox Code Playgroud)
在所有这些方法中,哪些方法在复制中断的情况下是安全的(例如:杀死 Python 进程)?列表中的最后一个看起来不错。
安全我的意思是:如果一个 1 GB 的文件复制没有 100% 完成(假设它在复制过程中被中断,在 400MB 之后),文件大小不应在文件系统中报告为1GB,它应该:
最糟糕的是,最终的文件大小为先写(内部与fallocate或ftruncate?)。如果复制被中断,这将是一个问题:通过查看文件大小,我们会认为文件被正确写入。
许多增量备份程序(我正在编写一个)使用“filename+mtime+fsize”来检查文件是否必须被复制或者它是否已经存在(当然更好的解决方案是 SHA256 源文件和目标文件,但这不是每次同步都完成,太耗时;这里偏离主题)。
所以我想确保fsize在复制实际文件内容之前,“复制文件”功能不会立即存储最终文件大小(然后它可能会欺骗比较)。
注意:我问这个问题是因为,虽然shutil.filecopy在 Python 3.7 及以下版本上相当直接,请参阅源代码(或多或少是上面的幼稚方法),但在 Python 3.9 上似乎要复杂得多,请参阅源代码,有许多不同的情况适用于 Windows、Linux、MacOS、“快速复制”技巧等。
假设destfile在复制之前不存在,则根据您对安全的定义,简单的方法是安全的。
shutil.copyfileobj()并shutil.copyfile()在排名中紧随其后。
shutils.copy()是下一个,也shutils.copy2()将是最后一个。
解释:
文件系统的工作是根据应用程序请求保证一致性。如果您仅将 X 字节写入文件,则文件大小将仅占这 X 字节。
因此,像naive方法那样直接进行FS操作是可行的。
现在的问题是这些高级函数如何处理文件系统。
API 没有说明如果 python 在复制过程中崩溃会发生什么,但事实上每个人都期望这些函数的行为与 Unix 类似cp,即不会扰乱文件大小。
假设 CPython 的维护者不想打破人们的期望,那么根据您的定义,所有这些函数都应该是安全的。
也就是说,AFAICT 在任何地方都不能保证这一点。
shutil.copyfileobj()然而,shutil.copyfile()他们的 API 明确承诺不复制元数据,因此他们不太可能尝试设置大小。
shutils.copy()不会尝试设置文件大小,仅设置模式,并且在大多数文件系统中设置大小和模式需要两种不同的文件系统操作,因此它应该仍然是安全的。
shutils.copy2()说它会复制元数据,如果你查看它的源代码,你会发现它只在复制数据后复制元数据,所以即使这样也应该是安全的。更重要的是,复制元数据并不会复制大小。
因此,只有当 python 使用的某些内部函数尝试使用 、 或类似函数进行优化时,这才会成为问题,ftruncate()考虑fallocate()到编写系统 API 的人(如 python 维护者)非常了解人们的期望,这种情况不太可能发生。