在整理照片、同步项目、迁移备份盘的时候,经常碰到同一个需求:把两个文件夹里的文件名拉出来对比,找出两边同名的那一批文件。这个需求听起来简单,真手动操作却很痛苦——文件夹套文件夹,数量一多,肉眼根本看不过来。这篇文章直接给出一套可落地的方案,包含 PowerShell、Python、批处理三种脚本实现,外加已有工具的处理思路,全部围绕“只对比文件名”这个核心场景展开,不求对比内容,不碰哈希值,目的就是快速定位两边存在同名文件的位置。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 对比维度 | 只对比文件名,不对比文件内容、大小、修改时间 |
| 输入要求 | 两个本地文件夹路径,支持网络映射盘 |
| 子目录处理 | 支持递归扫描子目录,也可以只扫顶层 |
| 输出结果 | 列出两边同名的文件名,以及文件所在完整路径 |
| 实现方式 | PowerShell 脚本 / Python 脚本 / 批处理 bat |
| 批量能力 | 支持一次处理大量文件,脚本自动扫描整个目录树 |
| 导出格式 | 支持控制台输出、CSV 导出、TXT 导出 |
| 运行平台 | Windows 优先,Python 方案可扩展到 Linux / macOS |
| 是否需要安装额外软件 | PowerShell 方案系统自带,Python 方案需安装 Python 运行环境 |
| 适合场景 | 备份同步前检查、照片去重、项目文件一致性核对、迁移前预检 |
从材料看,这是一个纯本地文件处理需求,不涉及模型部署、显存占用和 GPU 推理,所以本文重点围绕脚本实现、运行验证、批量处理效率、边界场景和错误排查展开。下面直接进入具体方案。
2. 适用场景与使用边界
“只对比文件名”这个约束条件非常明确。它适用于以下场景:
- 迁移文件前,想先知道两个目录里哪些文件重名,避免覆盖或漏拷。
- 整理多年累积的照片、视频素材目录,找出两边可能重复拍摄或重复下载的文件。
- 后端项目重构时,对比新旧代码目录里的资源文件,定位同名但可能被替换的文件。
- 备份目录与源目录做一致性粗查,同名文件存在,说明备份关系基本对应。
- 从旧硬盘拷贝数据到新硬盘后,抽查复制是否完整,同名文件是基础判断条件。
但这个方案也有明确的边界,必须说清楚:
- 同名文件不等于内容相同。文件名相同只是第一层信号,如果两个文件内容不同但名字一样,脚本依然会判定为重复。内容是否一致,需要再配合大小、修改时间、哈希值等手段进一步确认。
- 不同名文件不代表内容不重复。同一张图片复制后改名,文件名对比完全看不出来,这不是本方案能解决的问题。
- 对比结果只提供“哪些文件名相同”,不自动删除任何文件。所有脚本只做分析和输出,删除操作必须人工确认。
- 涉及他人版权素材、个人隐私数据、工作机密文件时,使用这类脚本只做文件名层面的技术处理,删除、复制、分发都必须符合授权约定和相关法规。
搞清楚边界之后,下面进入具体实现。三种方案各有优势,读者可以根据自己的环境选择:Windows 上不想装任何东西,直接用 PowerShell;需要跨平台或者后续想扩展内容对比,选 Python;就想双击运行、不看代码逻辑,用批处理 bat。
3. 环境准备与前置条件
这里给出一个通用检查清单,不绑定具体版本,读者按自己电脑实际情况对号入座即可。
PowerShell 方案:
- 操作系统:Windows 7 及以上。Windows 10、Windows 11 自带 Windows PowerShell 5.1,无需额外安装。
- 执行策略:脚本运行时如果提示“禁止运行脚本”,需要先放开当前用户的执行策略。
- 磁盘空间:脚本本身几乎不占空间,但如果有几万个文件,结果导出时建议预留几十 MB 日志空间。
- 路径权限:需要确保脚本有权限读取两个目录。如果目标文件夹在系统盘深处或者网络共享位置,需要注意访问权限。
Python 方案:
- 操作系统:Windows / Linux / macOS 均可。
- Python 运行环境:建议 Python 3.6 及以上,不需要任何第三方依赖库,只用标准库 os 和 sys。
- 命令行工具:Windows 用户可以在 CMD 或 PowerShell 中运行,也可以直接在 VS Code 终端里运行。
- 中文编码:Windows 下控制台输出中文文件名容易出现乱码,建议了解 chcp 65001 和 PYTHONIOENCODING 的相关设置。
批处理方案:
- 操作系统:Windows 原生命令行环境。
- 对脚本编码敏感。bat 文件如果包含中文注释,需要以 ANSI 或 GBK 编码保存,否则可能乱码或报语法错误。
- 批处理方案适合简单场景,文件名中包含特殊字符时处理起来会比较吃力。
4. 方案一:PowerShell 脚本实现
PowerShell 是 Windows 环境下处理这类问题最顺手的方式,不需要安装任何软件,脚本也足够直观。下面给出完整脚本。
# 对比两个文件夹中的文件名,找出两边同名文件 # 使用方式:修改 $folder1 和 $folder2 为实际路径,然后运行脚本 $folder1 = "D:\Backup\Source" $folder2 = "D:\Backup\Target" $includeSubdir = $true $outputCsv = "D:\Backup\duplicate_names.csv" # 递归获取文件对象 $files1 = Get-ChildItem -Path $folder1 -Recurse:$includeSubdir -File $files2 = Get-ChildItem -Path $folder2 -Recurse:$includeSubdir -File # 以文件名作为 key,构建字典;同名文件合并完整路径 $map1 = @{} foreach ($file in $files1) { $fileName = $file.Name if ($map1.ContainsKey($fileName)) { $map1[$fileName] = $map1[$fileName] + "|" + $file.FullName } else { $map1[$fileName] = $file.FullName } } $map2 = @{} foreach ($file in $files2) { $fileName = $file.Name if ($map2.ContainsKey($fileName)) { $map2[$fileName] = $map2[$fileName] + "|" + $file.FullName } else { $map2[$fileName] = $file.FullName } } # 取两个 key 集合的交集 $duplicateNames = $map1.Keys | Where-Object { $map2.ContainsKey($_) } # 输出到控制台 Write-Host "找到同名文件数量: $($duplicateNames.Count)" foreach ($name in $duplicateNames) { Write-Host "========================================" Write-Host "文件名: $name" Write-Host "位于文件夹1:" $map1[$name].Split("|") | ForEach-Object { Write-Host " $_" } Write-Host "位于文件夹2:" $map2[$name].Split("|") | ForEach-Object { Write-Host " $_" } } # 导出 CSV 结果 $results = foreach ($name in $duplicateNames) { [PSCustomObject]@{ 文件名 = $name 文件夹1路径 = $map1[$name] 文件夹2路径 = $map2[$name] } } $results | Export-Csv -Path $outputCsv -NoTypeInformation -Encoding UTF8 Write-Host "结果已导出到: $outputCsv"使用方法:
- 把上面的代码复制到记事本,保存为
Compare-FolderNames.ps1。 - 右键脚本文件,选择“使用 PowerShell 运行”,或者打开 PowerShell 窗口,进入脚本所在目录后执行:
powershell -ExecutionPolicy Bypass -File .\Compare-FolderNames.ps1- 如果遇到“无法加载文件,因为在此系统上禁止运行脚本”的提示,执行下面命令放开当前用户执行策略:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned- 脚本运行完成后,控制台会输出同名文件清单,同时会在指定路径生成 CSV 文件,方便后续用 Excel 筛选查看。
几个关键点说明:
Get-ChildItem -File只取文件,不会把文件夹目录本身算进去。$includeSubdir = $true表示递归子目录;如果只对比顶层文件,改成$false。- 同一目录里可能本身就有同名文件,比如
D:\Backup\Source\a\photo.jpg和D:\Backup\Source\b\photo.jpg,脚本会把它们合并成同一条,用|分隔多个路径。 - 导出 CSV 时用
-Encoding UTF8,Excel 打开时可以直接看到中文文件名,不会出现乱码。 - 文件名区分大小写的问题。Windows 的文件系统默认不区分大小写,
Photo.JPG和photo.jpg在 Windows 下会被视为同名。如果需要在 Linux 或者 macOS 上使用,PowerShell 脚本需要对 key 做ToLower()处理,不过这里不过度扩展,Windows 用户直接使用即可。
5. 方案二:Python 脚本实现
Python 方案的优势是跨平台、逻辑清晰,而且后续想升级成“文件名 + 大小 + 修改时间”多维对比也容易扩展。下面是完整脚本,只使用标准库,不需要 pip 安装任何第三方包。
# -*- coding: utf-8 -*- """ 对比两个文件夹中的文件名,找出两边同名文件 支持递归子目录,输出结果到控制台和文本文件 用法:python compare_folders.py """ import os import sys from collections import defaultdict def scan_files(folder): """ 递归扫描文件夹,返回一个字典: key 为文件名,value 为完整路径列表 """ file_map = defaultdict(list) for root, dirs, files in os.walk(folder): for name in files: full_path = os.path.join(root, name) file_map[name].append(full_path) return file_map def main(): # 在这里修改两个文件夹路径 folder1 = r"D:\Backup\Source" folder2 = r"D:\Backup\Target" # 如果路径不存在,直接退出 if not os.path.isdir(folder1) or not os.path.isdir(folder2): print("错误:两个文件夹路径必须真实存在") sys.exit(1) print(f"正在扫描文件夹1: {folder1}") map1 = scan_files(folder1) print(f"文件夹1 文件总数: {sum(len(v) for v in map1.values())}") print(f"正在扫描文件夹2: {folder2}") map2 = scan_files(folder2) print(f"文件夹2 文件总数: {sum(len(v) for v in map2.values())}") # 求两个字典 key 的交集,即同名文件 duplicate_names = set(map1.keys()) & set(map2.keys()) print(f"找到同名文件: {len(duplicate_names)} 个") output_lines = [] for name in sorted(duplicate_names): line = f"========================================\n" line += f"文件名: {name}\n" line += f" 文件夹1路径:\n" for p in map1[name]: line += f" {p}\n" line += f" 文件夹2路径:\n" for p in map2[name]: line += f" {p}\n" line += "\n" output_lines.append(line) print(line) # 导出结果到文本文件 output_txt = r"D:\Backup\duplicate_names_result.txt" with open(output_txt, "w", encoding="utf-8") as f: f.writelines(output_lines) print(f"结果已导出到: {output_txt}") if __name__ == "__main__": main()运行方法:
# 在脚本所在目录执行 python compare_folders.py如果运行后控制台中文乱码,在 Windows CMD 里先执行:
chcp 65001或者在执行 Python 时指定编码:
PYTHONIOENCODING=utf-8 python compare_folders.py这段脚本的行为说明:
os.walk(folder)会递归遍历所有子目录,同时拿到目录树下的所有文件。defaultdict(list)用来把同一个文件名对应的多个完整路径收集起来。比如两个不同子目录里都有report.pdf,路径都会被记录。set(map1.keys()) & set(map2.keys())是核心交集运算,直接把两边文件名相同的 key 筛出来,效率远高于两层循环。- 输出结果同时送到控制台和文本文件。文本文件用 UTF-8 编码保存,可以在任何现代编辑器中正常显示。
- 如果后续想升级对比维度,只需要在
scan_files函数里把(name, size)或(name, size, mtime)作为 key,就能实现“文件名 + 文件大小”一致才算重复,这里不再展开。
6. 方案三:批处理 bat 实现
如果不习惯 PowerShell 和 Python,Windows 原生的批处理方案也可以解决问题,适合快速查看、不想保存脚本的场景。原理很简单:先用DIR /S /B /A-D把两个文件夹的文件绝对路径分别导出到临时列表,再用两层FOR循环逐行比对文件名。
@echo off chcp 65001 >nul setlocal enabledelayedexpansion rem 在这里修改两个文件夹路径 set "folder1=D:\Backup\Source" set "folder2=D:\Backup\Target" rem 生成文件列表 dir /S /B /A-D "%folder1%" > "%temp%\list1.txt" dir /S /B /A-D "%folder2%" > "%temp%\list2.txt" echo 正在对比,请稍候... set count=0 for /f "delims=" %%a in (%temp%\list1.txt) do ( for /f "delims=" %%b in (%temp%\list2.txt) do ( if /i "%%~nxa"=="%%~nxb" ( set /a count+=1 echo 找到同名文件: %%~nxa echo 文件夹1: %%a echo 文件夹2: %%b echo ---------------------------------------- ) ) ) echo 对比完成,共找到 !count! 个同名文件。 endlocal pausebat 方案的优缺点非常直观:
- 优点:不依赖 Python,系统自带;直接双击运行,适合快速临时判断;代码逻辑简单,容易看懂。
- 缺点:性能差。两层 FOR 循环是 O(n*m) 复杂度,文件数量一两千时会明显变慢,文件上万后基本不可用。所以批处理方案只适合小规模目录对比,正式清理大量文件时不推荐。
- 文件名含特殊字符(如
&、!、^)时,FOR循环解析可能出错,需要转义或借助setlocal disabledelayedexpansion调整。 - bat 文件建议用 ANSI 或 GBK 编码保存中文内容,用 UTF-8 保存容易出现字符解析异常。
实际项目中,批处理更多是应急用,大批量场景建议优先选择 PowerShell 或 Python。
7. 已有工具方案
如果不想写脚本,也有现成的桌面工具可以做文件夹文件名对比。常见的重复文件查找工具如 DupeGuru、Duplicate Cleaner 等,虽然主打“内容哈希查重”,但一般也提供“文件名相同”这一类过滤条件。使用方式通常是:
- 下载并安装工具。
- 把两个文件夹拖入扫描范围。
- 选择“文件名相同”作为匹配条件,关闭“内容相同”条件。
- 执行扫描,等待结果。
这类工具的好处是有图形界面,操作直观,适合完全不想碰代码的用户。但也要注意几个问题:
- 部分工具支持“文件名相同 + 文件大小相同”组合对比,这会比纯文件名对比更接近真实重复,但也可能漏掉文件名相同但大小不同的情况。
- 工具可能会内置“移动/删除重复项”功能,使用删除操作前务必确认结果列表,避免误删。
- 版权和软件授权问题。下载工具尽量选择开源或官方渠道,不要使用来路不明的破解版。
- 大批量目录扫描时,工具的索引过程同样要耗费时间和内存,提前估算好规模。
如果文件夹数量很大、希望结果可以自动化处理和留痕,还是建议用脚本方案,输出结果更容易集成到自己的备份或同步流程中。
8. 资源占用与性能观察
这个需求不涉及 GPU、显存,但文件扫描和对比同样有性能问题需要观察。这里给出通用参考思路,具体耗时以实际目录规模为准。
影响性能的关键因素:
- 文件总数。文件数量直接决定扫描时间和内存占用。PowerShell 和 Python 都是先构建完整文件列表,再求交集,内存开销随文件数量线性增长。
- 目录层级深度。深层嵌套目录对
Get-ChildItem -Recurse和os.walk的影响主要体现在 IO 次数上,层次越深、越分散,扫描越慢。 - 是否走网络路径。对比网络共享文件夹时,延迟会明显拉高扫描耗时。同一批文件放在本地磁盘和放在 NAS 上,扫描时间可能相差数倍。
- 输出方式。控制台逐行打印比写入文件慢得多,文件数量很大时建议关闭控制台输出,直接把结果写入 CSV 或 TXT。
降低资源消耗的方法:
- 先在小范围目录上试跑一次,确认结果格式符合预期,再扩大到完整目录。
- 如果只需要找同名文件,不需要立即知道全部路径,可以先只在控制台输出文件名,路径后续筛选再补。
- 避免把结果文件放在被扫描的文件夹里。比如脚本把 CSV 输出到
D:\Backup\Source下的某个文件,下次扫描时该 CSV 也会被当成普通文件收集进名单,导致结果里混入自己。 - 文件数量过十万时,建议改用 Python 方案并配合
set运算,不要用 bat 的两层循环。 - 控制台中文输出乱码时,不要急着改脚本逻辑,先检查代码页设置是否已切换到 UTF-8。
- 批量任务稳定运行的标志是:扫描过程中没有报权限错误、没有出现空路径、结果数量稳定、重复运行两次数据一致。
从实际使用角度看,PowerShell 和 Python 脚本处理三五万文件通常只是几秒到几十秒的差异,瓶颈主要在磁盘 IO。如果两个文件夹在同一块机械硬盘上,同时频繁读取会导致寻道时间上升,有明显卡顿感。这时候可以把两个文件夹分别放在不同磁盘上扫描,或者耐心等待一轮扫描完成后再进行下一轮。
9. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| PowerShell 提示禁止运行脚本 | 系统执行策略默认 Restricted | 查看策略状态Get-ExecutionPolicy | 执行Set-ExecutionPolicy -Scope CurrentUser RemoteSigned后重试 |
| 脚本能找到目录但结果为空 | 两个文件夹里确实没有同名文件 | 检查两个文件夹路径是否正确、权限是否可读 | 先手动 DIR 抽查两边文件名,确认对比逻辑无误 |
| 中文文件名输出乱码 | PowerShell 控制台编码或 CSV 编码问题 | 检查代码页和文件编码 | 调整chcp 65001;Excel 打开 CSV 前导入 UTF-8 编码 |
| Python 脚本运行时提示路径不存在 | 直接复制的路径带引号或包含特殊字符 | 检查 raw string 写法r"D:\..." | 删除多余引号、空格,使用绝对路径 |
| 同名文件太多,结果刷屏 | 对比的两个文件夹高度重合 | 重定向输出到文件 | 修改脚本,把Write-Host改为写入 TXT/CSV |
| bat 脚本双击后窗口一闪而过 | 脚本语法错误或路径不存在 | 在 CMD 中直接运行 bat 查看报错 | 在脚本最后加pause查看错误信息;检查中文编码 |
| 扫描速度慢到无法接受 | 文件数量大、目录层级深、网络路径 | 先小目录测试,定位瓶颈 | 换 Python 方案,关闭控制台输出,结果只写文件 |
| 同一文件在两边目录中重复出现多条 | 一个目录里本身就有多个子目录包含同名文件 | 检查脚本输出路径列表 | 这是正常现象,脚本会把所有路径都列出来 |
| 结果文件被下次扫描当成输入文件 | 输出文件放在了被扫描目录内 | 检查输出路径所在位置 | 把输出目录放在扫描范围之外,或设置排除规则 |
| Linux / macOS 下脚本无法运行 | 路径分隔符或编码差异 | 确认系统类型 | Windows 路径写法改用/;脚本本身用 Python 跨平台版本 |
其中,最容易踩的坑有两个。第一,PowerShell 脚本完成后如果输出 CSV,要确认 CSV 文件没有生成在两个对比文件夹之一里面,否则下次扫描时结果文件会混进文件列表。第二,Python 脚本在 Windows 上处理大量文件时,如果路径过长超过系统默认限制,可能跳过部分文件,表现为结果不完整。此时需要确认目录是否启用了长路径支持,或者把素材先移动到更浅的目录层级再对比。
10. 最佳实践与使用建议
10.1 先小范围试跑,再全量执行
不管用哪种方案,第一次运行都先挑一个包含少量文件的子目录测试,确认输出格式符合预期。盲目对几十 GB 的目录全量跑,万一脚本路径写错或输出参数有问题,浪费时间。
10.2 结果文件与扫描目录隔离
脚本生成的 CSV、TXT 结果文件,一律放到扫描范围之外的目录,比如D:\Backup\compare_output\。否则下次扫描时,上一次的结果文件也会被纳入文件列表,影响结果准确性。
10.3 区分“仅查看”与“删除重复”两个阶段
文件名相同的文件,内容不一定相同。最佳实践是全量导出同名文件清单后,先用 Excel 或文本编辑器分类查看,再针对重点文件做二次确认,最后才考虑是否删除或覆盖。删除操作必须人工介入,脚本只提供位置线索。
10.4 重要数据先备份
如果目标目录是重要数据目录,执行任何删除、移动前务必备份。可以通过 3-2-1 原则管理备份,即至少 3 份副本、2 种不同介质、1 份异地或离线副本。文件名对比脚本本身不会修改数据,但后续人工处理时存在误操作风险。
10.5 批量任务留痕
如果是在生产环境或工作目录中做整理,建议每次对比都保留一份结果文件。文件名加日期后缀,如duplicate_names_20250101.csv,方便后续追溯。
10.6 隐私、版权与合规边界
处理他人电脑、公司服务器、公共共享文件夹时,注意数据隐私和授权问题。文件名对比本身是中性技术操作,但批量移动或删除文件前,必须确认数据来源合法、使用者具备相应权限。涉及版权素材、个人隐私、工作机密时,所有操作应限于授权范围。使用第三方工具时,也从官方或可信渠道下载,避免引入恶意软件。
10.7 扩展方向
如果文件名对比已满足需求,后续可以按需扩展:
- 文件名 + 文件大小 + 修改时间组合对比,准确率更高。
- 增加排除目录规则,比如跳过
.git、node_modules、Thumbs.db等无需关注的目录。 - 输出为 HTML 报告,带超链接直达文件位置。
- 集成到定时任务中,定期检查两个同步目录的文件名一致性问题。
11. 总结与下一步
这次整理的三种脚本方案,已经把“对比两个文件夹中的文件找出重复的(只对比文件名)”这个需求完整覆盖了。没有复杂依赖、不需要额外安装重型软件,PowerShell 和 Python 两种方案都能在 Windows 环境下直接使用,Python 方案还支持跨平台。
优先推荐 PowerShell 方案。系统自带、代码直接复制就能跑、输出 CSV 方便查看,对多数人来说是最省事的路径。如果熟悉 Python 或者需要更细粒度地控制扫描逻辑,Python 方案的可扩展性更好。bat 方案只建议在小目录、应急场景下偶尔用一次,不适合大规模文件对比。
最容易踩的坑集中在三点:结果文件放在扫描目录里导致自污染、中文编码没设置好导致输出乱码、把“同名”当成“内容重复”直接删除。所有脚本都只做分析和输出,数据安全的关键一步留给人工判断,这一点务必记住。
下一步建议直接创建一个测试目录,放几个同名文件,把 PowerShell 脚本跑通,确认输出结果符合预期。跑通之后再对真实目录操作,效率会高很多。