递归地比较两个目录以确保它们具有相同的文件和子目录

2024-04-18 23:51:14 发布

您现在位置:Python中文网/ 问答频道 /正文

据我观察,^{}是递归的,但不足以满足我的需要,至少在py2中是这样。我想比较两个目录及其包含的所有文件。这是否存在,或者我是否需要构建(例如,使用^{})。我更喜欢预先构建,在那里其他人已经完成了单元测试:)

实际的“比较”可以是草率的(例如,忽略权限),如果这有帮助的话。

我想要布尔型的,而且report_full_closure是打印报告。它也只沿着普通的街道。AFIAC,如果他们有任何东西在左或右方向只有这些是不同的方向。我用os.walk来构建它。


Tags: 文件report目录权限os报告单元测试方向
3条回答

report_full_closure()方法是递归的:

comparison = filecmp.dircmp('/directory1', '/directory2')
comparison.report_full_closure()

编辑:在OP编辑之后,我认为最好使用filecmp中的其他函数。我认为os.walk是不必要的;最好简单地通过common_dirs等生成的列表递归,尽管在某些情况下(大型目录树),如果实现得不好,这可能会导致最大递归深度错误。

下面是比较函数与filecmp模块的替代实现。它使用递归而不是os.walk,因此它稍微简单一些。但是,它不是简单地通过使用common_dirssubdirs属性递归的,因为在这种情况下,我们将隐式地使用默认的“浅层”文件比较实现,这可能不是您想要的。在下面的实现中,当比较同名文件时,我们总是只比较它们的内容。

import filecmp
import os.path

def are_dir_trees_equal(dir1, dir2):
    """
    Compare two directories recursively. Files in each directory are
    assumed to be equal if their names and contents are equal.

    @param dir1: First directory path
    @param dir2: Second directory path

    @return: True if the directory trees are the same and 
        there were no errors while accessing the directories or files, 
        False otherwise.
   """

    dirs_cmp = filecmp.dircmp(dir1, dir2)
    if len(dirs_cmp.left_only)>0 or len(dirs_cmp.right_only)>0 or \
        len(dirs_cmp.funny_files)>0:
        return False
    (_, mismatch, errors) =  filecmp.cmpfiles(
        dir1, dir2, dirs_cmp.common_files, shallow=False)
    if len(mismatch)>0 or len(errors)>0:
        return False
    for common_dir in dirs_cmp.common_dirs:
        new_dir1 = os.path.join(dir1, common_dir)
        new_dir2 = os.path.join(dir2, common_dir)
        if not are_dir_trees_equal(new_dir1, new_dir2):
            return False
    return True

filecmp.dircmp是一条路。但它不比较在两个比较目录中找到的具有相同路径的文件的内容。相反,filecmp.dircmp只查看文件属性。由于dircmp是一个类,您可以使用dircmp子类修复它,并重写它的phase3函数,该函数比较文件以确保比较内容,而不是只比较os.stat属性。

import filecmp

class dircmp(filecmp.dircmp):
    """
    Compare the content of dir1 and dir2. In contrast with filecmp.dircmp, this
    subclass compares the content of files with the same path.
    """
    def phase3(self):
        """
        Find out differences between common files.
        Ensure we are using content comparison with shallow=False.
        """
        fcomp = filecmp.cmpfiles(self.left, self.right, self.common_files,
                                 shallow=False)
        self.same_files, self.diff_files, self.funny_files = fcomp

然后可以使用此函数返回布尔值:

import os.path

def is_same(dir1, dir2):
    """
    Compare two directory trees content.
    Return False if they differ, True is they are the same.
    """
    compared = dircmp(dir1, dir2)
    if (compared.left_only or compared.right_only or compared.diff_files 
        or compared.funny_files):
        return False
    for subdir in compared.common_dirs:
        if not is_same(os.path.join(dir1, subdir), os.path.join(dir2, subdir)):
            return False
    return True

如果您希望重用此代码片段,则此代码片段将专用于公共域或您选择的Creative Commons CC0(除了SO提供的默认许可证CC-BY-SA)。

相关问题 更多 >