如何使用哈希对比两个目录的大量文件并识别相同文件?
批量哈希匹配新旧GIS数据目录的解决方案
针对你迁移GIS数据后需要建立新旧路径对应关系的需求,以下是两种高效的批量哈希对比方案,支持排除无需处理的文件:
方案一:Python脚本(跨平台,灵活定制排除规则)
该脚本会遍历新旧目录,计算每个文件的MD5哈希(内容未修改时可精准匹配),自动排除指定类型/目录的文件,最终生成新旧路径对应表。
import os import hashlib from collections import defaultdict def get_file_hash(file_path, chunk_size=4096): """分块计算文件MD5哈希,避免大文件占用过多内存""" hash_obj = hashlib.md5() with open(file_path, 'rb') as f: while chunk := f.read(chunk_size): hash_obj.update(chunk) return hash_obj.hexdigest() def build_hash_map(root_dir, exclude_patterns): """构建哈希值到文件路径的映射,跳过排除项""" hash_map = defaultdict(list) for dirpath, _, filenames in os.walk(root_dir): for filename in filenames: file_path = os.path.abspath(os.path.join(dirpath, filename)) # 检查是否命中排除规则 exclude = False for pattern in exclude_patterns: if pattern in file_path or file_path.endswith(pattern): exclude = True break if exclude: continue file_hash = get_file_hash(file_path) hash_map[file_hash].append(file_path) return hash_map def generate_path_mappings(old_root, new_root, exclude_patterns): """生成新旧路径对应表并保存到文件""" old_hash_map = build_hash_map(old_root, exclude_patterns) new_hash_map = build_hash_map(new_root, exclude_patterns) # 筛选两边都存在的哈希值(对应相同文件) common_hashes = set(old_hash_map.keys()) & set(new_hash_map.keys()) path_mappings = [] for h in common_hashes: # 按顺序配对路径(若存在重复文件,需后续手动校验) for old_p, new_p in zip(old_hash_map[h], new_hash_map[h]): path_mappings.append((old_p, new_p)) # 保存为制表符分隔的文本文件,方便后续批量替换 with open('gis_path_mappings.txt', 'w', encoding='utf-8') as f: f.write("旧路径\t新路径\n") for old_p, new_p in path_mappings: f.write(f"{old_p}\t{new_p}\n") print(f"路径对应表已生成:gis_path_mappings.txt") return path_mappings # 配置参数(替换为你的实际路径和排除规则) OLD_ONLINE_DIR = "/path/to/online-drive/gis-data" NEW_LOCAL_DIR = "/path/to/local-storage/gis-data" EXCLUDE_RULES = [".jpg", ".png", "historical-backup"] if __name__ == "__main__": generate_path_mappings(OLD_ONLINE_DIR, NEW_LOCAL_DIR, EXCLUDE_RULES)
使用说明:
- 替换脚本中的路径和排除规则,匹配你的实际需求
- 运行脚本后,
gis_path_mappings.txt文件会保存所有匹配成功的新旧路径对 - 若存在同一哈希对应多个文件的情况,需手动确认配对关系(通常是重复数据)
方案二:命令行工具(无需编程,快速实现)
Linux/macOS(Bash脚本)
#!/bin/bash # 配置参数 OLD_DIR="/path/to/online-drive/gis-data" NEW_DIR="/path/to/local-storage/gis-data" EXCLUDE_TYPES="*.jpg *.png" EXCLUDE_DIRS="historical-backup" # 生成旧目录哈希表(排除指定文件/目录) find "$OLD_DIR" -type f \ -not \( -name "$EXCLUDE_TYPES" -o -path "*$EXCLUDE_DIRS*" \) \ -exec md5sum {} \; > old_hashes.txt # 生成新目录哈希表 find "$NEW_DIR" -type f \ -not \( -name "$EXCLUDE_TYPES" -o -path "*$EXCLUDE_DIRS*" \) \ -exec md5sum {} \; > new_hashes.txt # 匹配哈希并输出路径对应关系 join -1 1 -2 1 <(sort old_hashes.txt) <(sort new_hashes.txt) | awk '{print $2 "\t" $3}' > gis_path_mappings.txt echo "路径对应表已生成:gis_path_mappings.txt"
Windows(PowerShell脚本,无需额外模块)
# 配置参数 $oldDir = "C:\path\to\online-drive\gis-data" $newDir = "C:\path\to\local-storage\gis-data" $excludePatterns = @("*.jpg", "*.png", "*historical-backup*") # 构建旧路径哈希映射 $oldHashMap = @{} Get-ChildItem -Path $oldDir -Recurse -File | Where-Object { $file = $_ !($excludePatterns | Where-Object { $file.FullName -like $_ }) } | ForEach-Object { $hash = (Get-FileHash -Path $_.FullName -Algorithm MD5).Hash if (-not $oldHashMap.ContainsKey($hash)) { $oldHashMap[$hash] = $_.FullName } } # 匹配新路径并生成对应表 $pathMappings = @() Get-ChildItem -Path $newDir -Recurse -File | Where-Object { $file = $_ !($excludePatterns | Where-Object { $file.FullName -like $_ }) } | ForEach-Object { $hash = (Get-FileHash -Path $_.FullName -Algorithm MD5).Hash if ($oldHashMap.ContainsKey($hash)) { $pathMappings += [PSCustomObject]@{ OldPath = $oldHashMap[$hash] NewPath = $_.FullName } } } $pathMappings | Export-Csv -Path gis_path_mappings.csv -NoTypeInformation -Encoding utf8 Write-Host "路径对应表已生成:gis_path_mappings.csv"
关键注意事项
- 哈希算法:MD5足够满足内容匹配需求(速度快),若担心碰撞可替换为SHA256(稍慢)
- 大文件处理:两种方案均支持分块/流式处理大文件,不会占用过多内存
- 重复文件:若同一哈希对应多个路径,需手动校验确认配对关系,避免路径替换错误
内容的提问来源于stack exchange,提问作者Tanner
相关产品推荐
相关产品推荐

