简单方法避免在输出相同时覆盖文件

3 投票
4 回答
4009 浏览
提问于 2025-04-17 09:28

我有一个用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 GPetr Viktoringeccojoel3000 的代码和想法:

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 通常会比一行的长度大,这样可以减少读取的次数。

撰写回答