简单方法避免在输出相同时覆盖文件
我有一个用Python写的C++代码生成器,它会生成很多源文件。大部分情况下,只有一个文件会发生变化,但因为生成器会重新生成所有文件,所以所有文件都会被重新构建。有没有办法让Python不覆盖这些文件,或者让cmak使用校验和来判断哪些文件需要重新构建,而不是仅仅依靠文件的修改日期呢?
我在想,像这样在Python中实现应该很简单:如果我能把
with open('blah', 'w') as f:
替换成这个:
with open_but_only_overwrite_if_total_output_is_different('blah', 'w') as f:
有什么好的方法可以做到这一点吗?
4 个回答
3
可以使用 filecmp 这个模块,具体可以查看这个链接:http://docs.python.org/library/filecmp.html。
你可以把新文件写入一个临时目录,然后和你正在使用的目录进行比较,找出那些有变化的文件。最后,把这些变化的文件转移过来,然后删除临时目录。
3
我建议你自己写一个类似文件的对象,步骤如下:
__enter__
: 创建一个临时文件__exit__
: 比较临时文件和旧文件的内容(如果旧文件存在的话)。如果内容不一样,就用临时文件替换掉旧文件
这篇文章对理解with
语句很有帮助:理解Python的"with"语句
5
结合了 Neil G、Petr Viktorin、gecco 和 joel3000 的代码和想法:
import contextlib
@contextlib.contextmanager
def write_on_change(filename):
with tempfile.NamedTemporaryFile(delete=False) as f:
yield f
tempname = f.name
try:
overwrite = not filecmp.cmp(tempname,filename)
except (OSError,IOError):
overwrite = True
if overwrite:
shutil.copyfile(tempname,filename)
os.unlink(tempname)
这里有一些小的补充(希望能有所改善):
shutil.copyfile
只会把tempname
的内容复制到filename
,同时保留一些文件的元数据,比如文件的权限和所有权。filecmp.cmp
会检查文件的大小,如果大小不一样就返回False
。如果文件很大,而且有东西被追加到文件末尾,这样的检查可以加快速度。它还会一次读取和比较 bufsize = 8*1024 字节,而不是一行一行地读取。bufsize
通常会比一行的长度大,这样可以减少读取的次数。