检查目录中是否添加、删除或修改了任何文件

7
我正在尝试编写一个Python脚本,以获取目录中所有文件的md5sum(在Linux上)。 我相信我已经在下面的代码中完成了这个任务。
我希望能够运行此脚本以确保目录中没有更改的文件,并且没有添加或删除任何文件。
问题是,如果我更改目录中的文件,然后又将其更改回来。我从运行下面的函数中得到不同的结果。(即使我已将修改的文件改回原样)
有人能解释一下吗? 如果您想到了解决方法,请告诉我。
def get_dir_md5(dir_path):
    """Build a tar file of the directory and return its md5 sum"""
    temp_tar_path = 'tests.tar'
    t = tarfile.TarFile(temp_tar_path,mode='w')  
    t.add(dir_path)
    t.close()

    m = hashlib.md5()
    m.update(open(temp_tar_path,'rb').read())
    ret_str = m.hexdigest()

    #delete tar file
    os.remove(temp_tar_path)
    return ret_str

编辑: 正如这些好心人所回答的那样,tar似乎包含了日期修改等头部信息。使用zip或其他格式会有什么不同吗?

还有其他解决方法吗?

4个回答

8

就像其他答案所提到的那样,即使tar文件内容相同,由于tar元数据变化或文件顺序变化,两个tar文件也可以不同。您应该直接运行文件数据上的校验和,并对目录列表进行排序,以确保它们始终按照相同的顺序排列。如果要在校验和中包含一些元数据,请手动包含。

以下是未经测试的示例使用os.walk

import os
import os.path
def get_dir_md5(dir_root):
    """Build a tar file of the directory and return its md5 sum"""

    hash = hashlib.md5()
    for dirpath, dirnames, filenames in os.walk(dir_root, topdown=True):

        dirnames.sort(key=os.path.normcase)
        filenames.sort(key=os.path.normcase)

        for filename in filenames:
            filepath = os.path.join(dirpath, filename)

            # If some metadata is required, add it to the checksum

            # 1) filename (good idea)
            # hash.update(os.path.normcase(os.path.relpath(filepath, dir_root))

            # 2) mtime (possibly a bad idea)
            # st = os.stat(filepath)
            # hash.update(struct.pack('d', st.st_mtime))

            # 3) size (good idea perhaps)
            # hash.update(bytes(st.st_size))

            f = open(filepath, 'rb')
            for chunk in iter(lambda: f.read(65536), b''):
                hash.update(chunk)

    return hash.hexdigest()

2
很棒的答案。与我概述的基本方法相同,但是用代码实现。不错。 - the wolf

7
TAR文件头包含一个文件的修改时间字段;即使更改是后来被改回,改变文件的行为也会导致TAR文件头不同,从而导致不同的哈希值。

谢谢。我猜没有选项可以告诉它不包括文件头? - Greg
1
即使你可以,也不能保证TAR文件中的文件顺序是一致的。你可以做一些计算目录中每个文件的哈希值的操作,然后创建一个基于这些值的哈希,这将严格告诉你文件内容是否相同。 - Joe

3
您无需创建TAR文件即可完成您所提出的操作。
以下是您的解决方案算法:
  1. 遍历目录树;
  2. 获取每个文件的md5签名;
  3. 对签名进行排序;
  4. 获取所有单个文件签名的文本字符串的md5签名。
最终得到的单一签名就是您要寻找的内容。
实际上,您甚至不需要Python。您可以这样做:
find /path/to/dir/ -type f -name *.py -exec md5sum {} + | awk '{print $1}'\
| sort | md5sum

1

tar文件包含除实际文件内容之外的元数据,例如文件访问时间、修改时间等。即使文件内容没有更改,tar文件实际上也会有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接