代码之家  ›  专栏  ›  技术社区  ›  langlauf.io

python3:基于文件内容递归比较两个目录

  •  0
  • langlauf.io  · 技术社区  · 6 年前

    我有两个目录,其中包含一堆文件和子文件夹。 我想检查两个目录中的文件内容是否相同(忽略文件名)。子文件夹结构也应该相同。

    我看着 filecmp.dircmp 但这并没有帮助,因为它不考虑文件内容;没有 shallow=False 选项与 filecmp.dircmp() here .

    工作区 this 因此,答案也不起作用,因为它考虑了文件名。

    做比较最好的方法是什么?

    1 回复  |  直到 6 年前
        1
  •  1
  •   kabanus    6 年前

    开始了。虽然还需要更多的测试,但在小测试之后,这似乎是可行的。同样,这可能非常长,这取决于文件的数量和大小:

    import filecmp
    import os
    from collections import defaultdict
    from sys import argv
    
    def compareDirs(d1,d2):
        files1 = defaultdict(set)
        files2 = defaultdict(set)
        subd1  = set()
        subd2  = set()
        for entry in os.scandir(d1):
            if entry.is_dir(): subd1.add(entry)
            else: files1[os.path.getsize(entry)].add(entry)
        #Collecting first to compare length since we are guessing no
        #match is more likely. Can compare files directly if this is
        # not true.
        for entry in os.scandir(d2):
            if entry.is_dir(): subd2.add(entry)
            else: files2[os.path.getsize(entry)].add(entry)
    
        #Structure not the same. Checking prior to content.
        if len(subd1) != len(subd2) or len(files1) != len(files2): return False
    
        for size in files2:
            for entry in files2[size]:
                for fname in files1[size]: #If size does not exist will go to else
                    if filecmp.cmp(fname,entry,shallow=False): break
                else: return False
                files1[size].remove(fname)
                if not files1[size]: del files1[size]
    
        #Missed a file
        if files1: return False
    
        #This is enough since we checked lengths - if all sd2 are matched, sd1
        #will be accounted for.
        for sd1 in subd1:
            for sd2 in subd2:
                if compareDirs(sd1,sd2): break
            else: return False #Did not find a sub-directory
            subd2.remove(sd2)
    
        return True
    
    print(compareDirs(argv[1],argv[2]))
    

    递归地输入两个目录。比较第一级的文件-如果不匹配则失败。然后尝试将第一个目录中的任何子目录与下一个目录中的任何子目录递归匹配,直到所有子目录都匹配为止。

    这是最天真的解决方案。可能遍历树,只有匹配的大小和结构在一般情况下是有益的。在这种情况下,函数看起来很相似,除了我们比较 getsize 而不是使用 filecmp ,并保存匹配的树结构,以便第二次运行更快。

    当然,对于一些结构和大小完全相同的子目录,我们仍然需要比较匹配的所有可能性。