要在 Python 脚本中排除特定类型的文件或目录,你可以修改compare_directories
函数,添加过滤逻辑。以下是增强后的代码,支持通过命令行参数指定要排除的文件或目录模式:
import os
import sys
import filecmp
import argparse
from datetime import datetime
import fnmatchdef compare_files(file1, file2, verbose=False):"""比较两个文件的内容、大小和修改时间"""try:# 检查文件是否存在if not os.path.exists(file1):return False, f"文件不存在: {file1}"if not os.path.exists(file2):return False, f"文件不存在: {file2}"# 获取文件基本信息stat1 = os.stat(file1)stat2 = os.stat(file2)# 比较文件大小size_match = stat1.st_size == stat2.st_size# 比较修改时间(精确到秒)mtime1 = datetime.fromtimestamp(stat1.st_mtime)mtime2 = datetime.fromtimestamp(stat2.st_mtime)mtime_match = mtime1 == mtime2# 比较文件内容content_match = filecmp.cmp(file1, file2, shallow=False)if verbose:print(f"文件1: {file1}")print(f"文件2: {file2}")print(f"大小匹配: {size_match}")print(f"修改时间匹配: {mtime_match}")print(f"内容匹配: {content_match}")print("-" * 50)return content_match and size_match and mtime_match, ""except Exception as e:return False, f"比较时出错: {str(e)}"def should_exclude(path, exclude_patterns):"""检查路径是否应被排除"""for pattern in exclude_patterns:if fnmatch.fnmatch(path, pattern):return Truereturn Falsedef compare_directories(dir1, dir2, verbose=False, recursive=True, exclude_patterns=None):"""递归比较两个目录的内容,支持排除特定文件和目录"""try:# 检查目录是否存在if not os.path.isdir(dir1):return False, f"目录不存在: {dir1}"if not os.path.isdir(dir2):return False, f"目录不存在: {dir2}"# 初始化排除模式if exclude_patterns is None:exclude_patterns = []# 使用 filecmp.dircmp 进行目录比较dcmp = filecmp.dircmp(dir1, dir2)# 过滤排除的文件和目录filtered_left_only = [item for item in dcmp.left_only if not should_exclude(item, exclude_patterns)]filtered_right_only = [item for item in dcmp.right_only if not should_exclude(item, exclude_patterns)]filtered_diff_files = [item for item in dcmp.diff_files if not should_exclude(item, exclude_patterns)]filtered_common_dirs = [item for item in dcmp.common_dirs if not should_exclude(item, exclude_patterns)]# 检查只在一个目录中存在的文件/目录if filtered_left_only or filtered_right_only:if verbose:if filtered_left_only:print(f"仅在 {dir1} 中存在: {filtered_left_only}")if filtered_right_only:print(f"仅在 {dir2} 中存在: {filtered_right_only}")return False, "目录内容不匹配"# 检查名称相同但内容不同的文件if filtered_diff_files or dcmp.funny_files:if verbose:if filtered_diff_files:print(f"文件内容不同: {filtered_diff_files}")if dcmp.funny_files:print(f"无法比较的文件: {dcmp.funny_files}")return False, "文件内容不匹配"# 递归比较子目录if recursive and filtered_common_dirs:for common_dir in filtered_common_dirs:sub_dir1 = os.path.join(dir1, common_dir)sub_dir2 = os.path.join(dir2, common_dir)match, message = compare_directories(sub_dir1, sub_dir2, verbose, recursive, exclude_patterns)if not match:return False, messagereturn True, ""except Exception as e:return False, f"比较时出错: {str(e)}"def main():"""主函数,处理命令行参数"""parser = argparse.ArgumentParser(description='比较文件或目录,支持排除特定文件或目录')parser.add_argument('path1', help='第一个文件或目录路径')parser.add_argument('path2', help='第二个文件或目录路径')parser.add_argument('-v', '--verbose', action='store_true', help='显示详细比较信息')parser.add_argument('-r', '--recursive', action='store_true', help='递归比较目录(默认启用)')parser.add_argument('--no-recursive', action='store_false', dest='recursive', help='不递归比较目录')parser.add_argument('-e', '--exclude', action='append', default=[], help='排除模式(支持通配符,如 *.pyc, __pycache__)')# 设置默认值parser.set_defaults(recursive=True)args = parser.parse_args()# 检查路径类型if os.path.isfile(args.path1) and os.path.isfile(args.path2):# 文件比较match, message = compare_files(args.path1, args.path2, args.verbose)if match:print(f"文件 '{args.path1}' 和 '{args.path2}' 匹配")else:print(f"文件 '{args.path1}' 和 '{args.path2}' 不匹配")if message:print(f"原因: {message}")sys.exit(1)elif os.path.isdir(args.path1) and os.path.isdir(args.path2):# 目录比较match, message = compare_directories(args.path1, args.path2, args.verbose, args.recursive, args.exclude)if match:print(f"目录 '{args.path1}' 和 '{args.path2}' 匹配")else:print(f"目录 '{args.path1}' 和 '{args.path2}' 不匹配")if message:print(f"原因: {message}")sys.exit(1)else:print("错误: 路径类型不匹配(一个是文件,另一个是目录)")sys.exit(1)if __name__ == "__main__":main()