我要学习

Python编程》笔记专栏现以开源到Gitee,其中包含我编写的示例程序文件和官方示例程序文件,以及md形式的笔记,欢迎各位给个Star。

比较目录树

找出目录间的差异

示例:dirdiff.py

#!/usr/bin/env python
"""
##############################################################################
用法:./dirdiff.py dir1 dir2
比较两个目录,找出只在其中一个目录中出现的文件。
这个版本使用os.listdir并把差异汇入列表。请注意这个脚本只检查文件名而不涉及文件内容。关于后者
的比较请参考diffall.py,它通过比较.read()结果来实现这方面的拓展。
##############################################################################
"""

import os
import sys


def reportdiffs(unique1, unique2, dir1, dir2):
    """
    为目录生成差异报告:comparedirs函数输出的一部分
    """
    if not (unique1 or unique2):
        print('{}和{}文件列表完全相同'.format(dir1, dir2))
    else:
        if unique1:
            print('{}的独有文件:'.format(dir1))
            for unique in unique1:
                print('...', unique)
        if unique2:
            print('{}的独有文件:'.format(dir2))
            for unique in unique2:
                print('...', unique)


def diff(seq1, seq2):
    """
    仅返回seq1的独有文件;
    也可以使用set(seq1) - set(seq2),不过集合内的顺序是随机的,
    所以会导致丢失具有平台依赖性的目录顺序。
    """
    return [item for item in seq1 if item not in seq2]


def comparedirs(dir1, dir2, files1=None, files2=None):
    """
    比较目录内容而非文件实际内容,可能需要listdir的bytes参数来处理
    某些系统平台上不可解码的文件名。
    """
    print('正在比较目录{}和{}下的文件列表'.format(dir1, dir2))
    files1 = os.listdir(dir1) if files1 is None else files1
    files2 = os.listdir(dir2) if files2 is None else files2
    unique1 = diff(files1, files2)
    unique2 = diff(files2, files1)
    reportdiffs(unique1, unique2, dir1, dir2)
    return unique1, unique2


def getargs():
    if len(sys.argv) != 3:
        print('用法:./dirdiff.py dir1 dir2')
        sys.exit()
    else:
        return sys.argv[1:]


def command():
    dir1, dir2 = getargs()
    comparedirs(dir1, dir2)


if __name__ == '__main__':
    command()

测试文件在Gitee(传送门)上。

运行:dirdiff.py

$ ./dirdiff.py compare1 compare2
正在比较目录compare1和compare2下的文件列表
compare1的独有文件:
... 95
... 98
... 99
compare2的独有文件:
... 50
... 51
... 52
... 53
... 54

找出目录树间的差异

导入的dirdiffcpall模块在Gitee上均已开源(传送门

示例:diffall.py

#!/usr/bin/env python
"""
##############################################################################
用法:./diffall.py dir1 dir2 [-v verbose(0/1)] [-b blocksize(int)]
递归地目录树比较:报告dir1和dir2各自的独有文件,报告dir1和dir2同名但内容不同的文件,dir1和
dir2下所有同名子目录及其目录进行相同操作。输出的末尾打印差异的总结。
##############################################################################
"""

import os
import sys
import dirdiff
import cpall

BLOCKSIZE = 1024 * 1024
VERBOSE = False


def intersect(seq1, seq2):
    """
    返回seq1和seq2的所有共有项;
    也可以用set(seq1) & set(seq2),不过集合内的顺序是随机的,
    故而可能丢失任何依赖于平台的目录顺序。
    """
    return [item for item in seq1 if item in seq2]


def comparetrees(dir1, dir2, diffs, verbose=VERBOSE, blocksize=BLOCKSIZE):
    """
    比较两个目录树中所有子目录和文件;使用二进制来阻止Unicode解码和换行符转换,
    因为目录树可能含有二进制文件和文本文件;
    可能需要listdir的bytes参数来处理某些平台上不可解码的文件名。
    """
    # 比较文件名列表
    print('-' * 79)
    print('正在比较目录{}和{}下的文件列表'.format(dir1, dir2))
    fns1 = os.listdir(dir1)
    fns2 = os.listdir(dir2)

    uniques1 = dirdiff.diff(fns1, fns2)
    uniques2 = dirdiff.diff(fns2, fns1)

    dirdiff.reportdiffs(uniques1, uniques2, dir1, dir2)

    if uniques1:
        for unique in uniques1:
            diffs.append('{}的独有文件:{}'.format(dir1, unique))

    if uniques2:
        for unique in uniques2:
            diffs.append('{}的独有文件:{}'.format(dir2, unique))

    # 比较共有文件的内容
    print('正在比较目录{}和{}下的共有文件内容'.format(dir1, dir2))
    commons = intersect(fns1, fns2)
    missed = commons[:]

    for fn in commons:
        fp1 = os.path.join(dir1, fn)
        fp2 = os.path.join(dir2, fn)
        if os.path.isfile(fp1) and os.path.isfile(fp2):
            missed.remove(fn)
            f1 = open(fp1, 'rb')
            f2 = open(fp2, 'rb')
            while True:
                bytes1 = f1.read(blocksize)
                bytes2 = f2.read(blocksize)
                if (not bytes1) and (not bytes2):
                    if verbose:
                        print('{}内容相同'.format(fn))
                    break
                if bytes1 != bytes2:
                    diffs.append('{}和{}下的{}内容不同'.format(dir1, dir2, fn))
                    print('{}内容不同'.format(fn))
                    break

    # 递归以比较共有目录
    for fn in commons:
        fp1 = os.path.join(dir1, fn)
        fp2 = os.path.join(dir2, fn)
        if os.path.isdir(fp1) and os.path.isdir(fp2):
            missed.remove(fn)
            comparetrees(fp1, fp2, diffs, verbose)

    # 同名但是一个是文件、一个是目录?
    for fn in missed:
        diffs.append('{}和{}下的{}不同类型但同名'.format(dir1, dir2, fn))
        print('{}不同类型但同名'.format(fn))


def getargs(verbose=VERBOSE, blocksize=BLOCKSIZE):
    if len(sys.argv) < 3 and len(sys.argv) > 5:
        print('用法:./dirdiff.py dir1 dir2')
        sys.exit()
    else:
        dir1, dir2 = sys.argv[1:3]

        if '-v' in sys.argv:
            verbose = cpall.getInt('-v')
        if '-b' in sys.argv:
            blocksize = cpall.getInt('-b')

        if verbose:
            verbose = True
        else:
            verbose = False

        return dir1, dir2, verbose, blocksize


def command():
    dir1, dir2, verbose, blocksize = getargs()
    diffs = []
    comparetrees(dir1, dir2, diffs, verbose, blocksize)
    print('=' * 79)

    if not diffs:
        print('完全相同')
    else:
        print('不同之处:', len(diffs))
        for diff in diffs:
            print('-', diff)


if __name__ == '__main__':
    command()

运行:diffall.py

$ ./diffall.py compare1 compare2
-------------------------------------------------------------------------------
正在比较目录compare1和compare2下的文件列表
compare1的独有文件:
... 95
... 98
... 99
compare2的独有文件:
... 50
... 51
... 52
... 53
... 54
正在比较目录compare1和compare2下的共有文件内容
10内容不同
9内容不同
-------------------------------------------------------------------------------
正在比较目录compare1/200和compare2/200下的文件列表
compare1/200的独有文件:
... 50
... 51
... 52
... 53
... 54
compare2/200的独有文件:
... 95
... 98
... 99
正在比较目录compare1/200和compare2/200下的共有文件内容
10内容不同
9内容不同
96不同类型但同名
97不同类型但同名
-------------------------------------------------------------------------------
正在比较目录compare1/201和compare2/201下的文件列表
compare1/201的独有文件:
... 50
... 51
... 52
... 53
... 54
compare2/201的独有文件:
... 95
... 98
... 99
正在比较目录compare1/201和compare2/201下的共有文件内容
10内容不同
9内容不同
96不同类型但同名
97不同类型但同名
96不同类型但同名
97不同类型但同名
===============================================================================
不同之处: 36
- compare1的独有文件:95
- compare1的独有文件:98
- compare1的独有文件:99
- compare2的独有文件:50
- compare2的独有文件:51
- compare2的独有文件:52
- compare2的独有文件:53
- compare2的独有文件:54
- compare1和compare2下的10内容不同
- compare1和compare2下的9内容不同
- compare1/200的独有文件:50
- compare1/200的独有文件:51
- compare1/200的独有文件:52
- compare1/200的独有文件:53
- compare1/200的独有文件:54
- compare2/200的独有文件:95
- compare2/200的独有文件:98
- compare2/200的独有文件:99
- compare1/200和compare2/200下的10内容不同
- compare1/200和compare2/200下的9内容不同
- compare1/200和compare2/200下的96不同类型但同名
- compare1/200和compare2/200下的97不同类型但同名
- compare1/201的独有文件:50
- compare1/201的独有文件:51
- compare1/201的独有文件:52
- compare1/201的独有文件:53
- compare1/201的独有文件:54
- compare2/201的独有文件:95
- compare2/201的独有文件:98
- compare2/201的独有文件:99
- compare1/201和compare2/201下的10内容不同
- compare1/201和compare2/201下的9内容不同
- compare1/201和compare2/201下的96不同类型但同名
- compare1/201和compare2/201下的97不同类型但同名
- compare1和compare2下的96不同类型但同名
- compare1和compare2下的97不同类型但同名
$ ./diffall.py compare1 compare2 -v 1 -b 1024
-------------------------------------------------------------------------------
正在比较目录compare1和compare2下的文件列表
compare1的独有文件:
... 95
... 98
... 99
compare2的独有文件:
... 50
... 51
... 52
... 53
... 54
正在比较目录compare1和compare2下的共有文件内容
35内容相同
60内容相同
0内容相同
1内容相同
10内容不同
……省略……
-------------------------------------------------------------------------------
正在比较目录compare1/200和compare2/200下的文件列表
……省略……
94内容相同
96不同类型但同名
97不同类型但同名
-------------------------------------------------------------------------------
正在比较目录compare1/201和compare2/201下的文件列表
……省略……
===============================================================================
不同之处: 36
- compare1的独有文件:95
- compare1的独有文件:98
……省略……

———————————————————————————————————————————

😃 学完博客后,是不是有所启发呢?如果对此还有疑问,欢迎在评论区留言哦。
如果还想了解更多的信息,欢迎大佬们关注我哦,也可以查看我的个人博客网站BeacherHou

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐