十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python批量重命名实战:应对几万个文件的命名规则整理

Python批量重命名实战:应对几万个文件的命名规则整理 几万个文件放在一起命名规则乱到没法归档手动改名既慢又容易漏。Python批量重命名是处理这类重复劳动最实用的方案一次写好规则再多人同时整理也不容易把文件名改乱。尤其是文件夹里全是带日期的素材、客户文件、报表、扫描件或是需要按照 Excel 清单去改 Word 文件名称时这个思路能帮你省下大量时间。这篇内容我会按真正的落地顺序拆解先判断命名需求再准备 Python 环境然后写几种最常用的重命名脚本。等你跑通小规模测试后再加防呆检查、日志和异常处理最后再放到几万个文件的真实目录里跑。文章更适合刚接触 Python、或者只会写 if/else 但没做过文件批处理的读者也适合想把自己的整理流程做成可复用脚本的人。1. 先分清你要处理的是哪一类命名问题1.1 多数批量命名可以归成三种模式先别急着搜“批量重命名代码”。命名规则不确认代码写得再漂亮都可能出错。常见需求其实能分成三类固定规则替换给所有文件加前缀、加后缀、去掉空格、把中文括号改成英文括号、统一大小写、改扩展名。顺序编号把一堆照片或扫描件按文件名、修改时间、创建时间排序后统一改成0001_name.jpg、0002_name.jpg这种带序号的名字。外部映射对照Excel 或 CSV 里有一列旧文件名、一列新文件名脚本按这个对应关系去改名。比如“根据 Excel 表格批量重命名对应的 Word 文件名称”就是这个场景。三种场景的处理逻辑完全不同。固定规则替换只需要处理字符串顺序编号要先确定排序方式外部映射则必须有准确的“新旧名称对应表”。如果不区分场景直接写一个“万能重命名脚本”很容易出现两个问题。第一个问题是脚本参数过多每次跑之前要反复确认第二个问题是没法预测结果遇到特殊情况时日志不清晰改错了都不知道是哪一步出的问题。1.2 建议先写一版命名规则样例我自己的习惯是不管需求多简单都先在纸上或表格里写两三个示例旧DSC_0001.jpg 新2025_客户A_0001.jpg 旧合同初稿.docx 新合同_初稿.docx 旧IMG_2381.png 新产品图_2381.png写样例的作用是让你提前关注几个容易被忽略的细节新文件名里要不要保留扩展名序号是三位还是四位日期放前缀还是后缀分隔符用下划线、中划线还是空字符原文件名里的空格、括号要不要一起处理。这些细节一旦确定代码结构基本就出来了。后面要做的是把节点拆开先改动一个目录里的少量文件确认结果符合预期再往大目录里放。2. Python 环境准备先确认你在哪个环境里跑2.1 命令行检查 Python 版本很多人不是不会写 Python而是环境没准备好导致脚本在系统之间跑来跑起。做批量文件重命名先确认你本机能不能正常调用 Python。Windows 下打开命令行输入python --version如果提示找不到命令最常见原因是安装时没有把 Python 写入环境变量。安装包里通常有 “Add python.exe to PATH” 选项安装时勾上就能省掉后面手工配置环境变量的麻烦。已经安装但没有勾选也可以在命令行里试试py --versionmacOS 和 Linux 大多自带 Python 3但自带版本可能和你需要的不完全一致。先输入python3 --version确认是 3.8 以上比较稳妥。新版 Python 命令在有些系统里是python3不是python这一点不用纠结认准当前终端能用的那个命令即可。2.2 第三方库尽量装在虚拟环境里如果只是用os.rename或pathlib做基础改名不需要安装额外库。但如果你要读 Excel 映射表通常会用到pandas、openpyxl或xlrd。这时候我建议新建一个虚拟环境避免不同项目之间依赖冲突。在项目目录下执行python -m venv venvWindows 激活虚拟环境venv\Scripts\activatemacOS 或 Linux 激活虚拟环境source venv/bin/activate激活后在终端里可以看到环境名前缀。此时再安装依赖pip install pandas openpyxl虚拟环境不是批量重命名的必须步骤但一旦你的 Python 环境里装了多个版本或各种项目包这个习惯能节省不少排查时间。毕竟很多报错根本不是代码问题而是库装在了别的解释器下面。2.3 用哪个编辑器不重要懂调试最关键VSCode、PyCharm、Notepad、系统自带记事本都能写这类脚本。VSCode 配置 Python 环境后能直接运行脚本也会显示语法错误。PyCharm 对新手更友好但项目结构略显重。两者都可以不需要争哪一个更好。关键是你会不会看错误信息。比如pip install时报权限错误说明当前 Python 环境没有写入权限优先考虑虚拟环境而不是盲目加sudo或管理员权限。再比如运行文件时显示ModuleNotFoundError: No module named pandas大概率不是代码错了而是你没有在激活的 venv 中安装 pandas或者运行脚本用的不是同一个 Python 解释器。3. 最常见的三类改名脚本先跑通这版再优化3.1 统一加前缀和后缀先看一个小而完整的示例。假设目录D:\待重命名里有一堆合同扫描件要统一加前缀合同_。from pathlib import Path folder Path(rD:\待重命名) prefix 合同_ for p in folder.iterdir(): if p.is_file() and not p.name.startswith(prefix): p.rename(p.with_name(prefix p.name))iterdir()会列出当前目录下的内容。p.is_file()用来过滤掉文件夹。p.with_name(...)会生成一个位于同一目录、但文件名不同的路径。这样就不用手动拼字符串里的路径分隔符避免 Windows 和 Linux 路径写法差异带来的坑。如果目标是把后缀统一加上比如此前导出的文件都没有.txt后缀from pathlib import Path folder Path(rD:\待重命名) suffix .txt for p in folder.iterdir(): if p.is_file() and not p.suffix.lower() suffix: p.rename(p.with_name(p.name suffix))这段代码有个明显缺陷如果文件原本是.pdf强行加上.txt会把内容不变、扩展名改成.txt可能反而更乱。所以“加后缀”需要先明确是给没有扩展名的文件补后缀还是给所有文件加自定义关键词前缀。不要混在一起用。3.2 把空格、中文括号等替换成统一字符文件名里如果有空格在命令行和很多工具里都不方便处理。常见做法是把空格替换成下划线。for p in folder.iterdir(): if p.is_file(): new_name p.name.replace( , _) new_name new_name.replace(, ().replace(, )) if new_name ! p.name: p.rename(p.with_name(new_name))同样如果文件名里有连续多个空格建议一次性处理掉import re for p in folder.iterdir(): if p.is_file(): new_name re.sub(r\s, _, p.name) if new_name ! p.name: p.rename(p.with_name(new_name))很多文件名不是“不能看”而是各种空格、制表符、中文符号混在一起。先做一个清洁步骤后面的搜索和归档会顺畅很多。3.3 按下标顺序统一编号目录里放了几百张图片希望按名称顺序排好后重新编号。可以先取出文件列表再按文件名字符串排序。files [p for p in folder.iterdir() if p.is_file()] files.sort(keylambda p: p.name.lower()) for index, p in enumerate(files, start1): new_name f{index:04d}_{p.name} p.rename(p.with_name(new_name))f{index:04d}会把 1 格式化成000110 格式化成0010。为什么要补零因为如果不补零排序时会出现1.jpg、10.jpg、2.jpg这种自然顺序错乱。补零后0001到0010能按文件管理器的人性化排序方式对齐。如果不需要保留原文件名只想用序号命名可以改成suffix p.suffix new_name f{index:04d}{suffix}但这里要特别提醒编号类脚本很容易把“第二次运行”搞砸。第一次运行后文件名已经变成了0001_xxx.jpg。第二次再执行同一段代码就会把所有文件重新编号一遍很可能把已经排好的顺序打乱。后面我会单独说如何让脚本可重复执行。4. 批量改名前先把防误改和干跑做进去4.1 目标路径冲突检查文件改名的最大风险不是跑得慢而是目标名和现有文件重名。在 Linux 和 macOS 上Path.rename在某些情况下会自动覆盖目标文件这会造成不可逆转的丢失。Windows 上虽然经常会报FileExistsError但不同环境行为不完全一致不能赌系统行为。所以在真正执行改名之前必须先检查目标路径是否已经存在。下面是一个比较安全的改名函数from pathlib import Path folder Path(rD:\待重命名) def safe_rename(src: Path, dst: Path): if not src.exists(): print(f源文件不存在: {src.name}) return False if src dst: return False if dst.exists(): print(f目标文件已存在跳过: {dst.name}) return False src.rename(dst) return True无论你用什么规则生成新文件名都建议先经过这个函数再执行真正的改名。虽然没有一个脚本能绝对避免所有误操作但“目标存在就跳过”这一个检查能挡住很多批量事故。4.2 特殊字符与非法文件名过滤Windows 文件名不能包含\ / : * ? |这类字符也不能以某些保留设备名命名。跨平台使用时要格外小心。建议在生成新文件名时先做一次清洗。import re def clean_name(name: str) - str: # 把连续空白替换成下划线 name re.sub(r\s, _, name) # 把 Windows 非法字符替换成下划线 name re.sub(r[\\/:*?|], _, name) # 去掉首尾多余的点或空格 name name.strip( .) return name清洗后再去执行改名。这个过程不需要太复杂也不需要你去判断每种操作系统的细节。统一把常见非法字符过滤掉能有效避免一批原来好端端的文件名因为脚本里的一个replace变成了不可用路径。4.3 干跑模式先输出改名计划再执行“干跑”听起来很专业其实就是在改名前把计划打印出来或写到文件里不真正操作文件。这是我会强烈建议新手养成的习惯。from pathlib import Path folder Path(rD:\待重命名) plan [] for p in folder.iterdir(): if not p.is_file(): continue new_name clean_name(p.name) if new_name p.name: continue dst p.with_name(new_name) plan.append((p, dst)) # 先打印前 20 条 for src, dst in plan[:20]: print(src.name, -, dst.name) print(f待处理文件数: {len(plan)})执行到这一步文件还没有被改动。看到待处理文件数后你可以人工确认数量是否符合预期。如果数量不对说明规则可能有漏网或误伤。确认没问题后再询问用户是否继续answer input(输入 y 开始执行) if answer.strip().lower() y: for src, dst in plan: safe_rename(src, dst)如果是在服务器上无法交互输入可以把这段改成“读取确认文件”。干跑的意义是让电脑先给出一个可预览、可复核的执行计划而不是直接用鼠标双击脚本后就“盲改”。4.4 日志和中断恢复几万个文件不是几秒就能处理完的。如果跑到一半停电、崩溃、用户点了停止后面会面临“不知道改到哪了”的尴尬。最好在改名前记录日志或者把整个计划先落盘。log_file folder / rename_plan.txt with log_file.open(w, encodingutf-8) as f: for src, dst in plan: f.write(f{src.name}\t{dst.name}\n)执行脚本时如果中断了下一次可以读取这个日志跳过已经处理过的文件。简单做法是每条记录都有一个待执行状态成功改名后在日志里标记done再次执行时跳过done。不用专门引入队列系统用一个文本日志就足够。重要的是别把所有文件一把全读进内存也别在失败后重复执行相同的改名逻辑。文件数量达到几万时能不能继续跑往往比能跑多快更重要。5. 从 Excel 表格映射到 Word 文件名的批量方案5.1 映射表字段尽量写成这样按 Excel 表格批量重命名 Word 文件是工作中很高频的需求。通常你会拿到一张表里面列着“旧名称”和“新名称”。我建议表格结构尽量简单序号旧文件名新文件名1合同_张三_2023.docx合同_张三_2024.docx2汇报_初版.docx汇报_终版.docx字段不要混在一列里也不要把文件路径写进去。如果文件在子目录前两列可以加“相对路径”列但更稳妥的做法是把待改名文件统一复制到一个目录里处理完再归档。5.2 pandas 读取 Excel 并逐个改名如果安装了pandas和openpyxl读取 Excel 非常方便。import pandas as pd from pathlib import Path folder Path(rD:\待改名) df pd.read_excel(rename_map.xlsx, dtypestr) for _, row in df.iterrows(): old_name str(row.get(旧文件名, )).strip() new_name str(row.get(新文件名, )).strip() if not old_name or not new_name: continue src folder / old_name dst folder / new_name if not src.exists(): print(找不到源文件:, old_name) continue if dst.exists(): print(目标文件已存在:, new_name) continue src.rename(dst) print(已重命名:, old_name, -, new_name)dtypestr可以避免 Excel 中类似0001的文本被读成数字1这个细节对文件名很重要。如果你没有pandas也可以只用标准库csv读取 CSV 文件。但 Excel 文件经常有多个 sheet数据里还可能存在空行用pandas处理起来更顺手。5.3 空值、重复项和后缀问题怎么处理映射方案最常见的坑不是代码本身而是表格数据和实际文件对不上。第一类问题是空值。Excel 里可能存在看似为空、其实是空格的行。建议在读取后先做数据清洗。df df.dropna(subset[旧文件名, 新文件名]) df[旧文件名] df[旧文件名].astype(str).str.strip() df[新文件名] df[新文件名].astype(str).str.strip() df df[df[旧文件名] ! None] df df[df[新文件名] ! None]第二类问题是重复。如果旧文件名重复同一个文件被规划成多个新名字脚本就会冲突。可以先检查重复项。duplicated df[df[旧文件名].duplicated(keepFalse)] if not duplicated.empty: print(存在重复的旧文件名请先处理 Excel)第三类问题是后缀不匹配。表的“新文件名”里的扩展名如果和 Word 原文件不同比如.doc改成.docx那本质上可能已经是格式转换问题不只是文件名改名。所以映射表中的后缀要尽量保持和源文件一致。如果 Excel 里的名称不带后缀可以在脚本中按实际类型补全但要注意doc和docx是两种后缀不能默认只补.docx。最后再看一个常见问题Excel 中旧文件名写的是绝对路径而待改名文件在另一个目录。跨目录映射时脚本会以为源文件也存在绝对路径下从而报找不到。最简单的处理办法Excel 只写文件名不写路径文件统一放到脚本指定的folder里。这样脚本清晰也不容易误操作其它目录。6. 几万个文件要怎么处理才不慢、不乱6.1 先想清楚是当前目录还是递归目录文件数量多时首先要想清楚你要处理的是当前目录还是包含所有子目录的递归目录。# 只处理当前目录和所有文件 for p in folder.iterdir(): ... # 只处理当前目录里的 jpg 图片 for p in folder.glob(*.jpg): ... # 递归处理所有子目录里的 jpg 图片 for p in folder.rglob(*.jpg): ...如果只改顶层文件用iterdir()或glob(*.pattern)。如果要把子目录里的文件也一起处理用rglob()。但要注意递归处理时如果你的改名规则可能会改到目录名建议先别把目录名也纳入规则。否则正在遍历时目录改了名字脚本可能找不到后续文件。稳妥做法是先处理文件再单独处理目录并且不做递归目录改名。6.2 不要轻易跨盘符也不要盲目上并发文件重命名是文件系统操作主要瓶颈通常不在 Python 运算而在磁盘读写。如果是普通本地硬盘脚本速度不会差到哪如果是网络共享盘瓶颈在网络延迟这时候你会觉得单个循环很慢。很多人遇到慢第一反应是开多线程、多进程。我不建议一开始就这么做。并发重命名会引入额外的问题命名冲突、日志乱序、资源竞争、错误难排查。先用单线程跑一个小目录记录时间评估整体耗时。如果确实到了大批量状态可以考虑用ThreadPoolExecutor但最大工作线程数也不要拉太高。每个 worker 都要调用文件系统太多 worker 会让磁盘排队反而更慢。from concurrent.futures import ThreadPoolExecutor def rename_one(pair): src, dst pair safe_rename(src, dst) pairs [(src, dst) for src, dst in plan if not dst.exists()] # 先小并发试一下 with ThreadPoolExecutor(max_workers4) as executor: list(executor.map(rename_one, pairs))这段代码只作为“确实需要并发时”的示例。真实任务里还是先确认单线程是否能接受再决定要不要并发。另一个更重的坑是跨盘符。Path.rename()默认是同一文件系统的重命名。如果源和目标不在同一个盘符或挂载点可能报跨设备错误。很多人把批量改名写成了“移动文件”这就会碰到这个问题。如果确实要把文件移动到另一个磁盘应该用shutil.move()并把“改名”和“移动”分成两步设计不要混在一个脚本里。6.3 让脚本幂等跑第二遍也不出错批量任务最好有一个特性幂等。意思是无论脚本执行一遍还是多遍结果都保持一致不会因为重复执行而把文件名改乱。加前缀的脚本可以判断是否已经有前缀if not p.name.startswith(prefix): p.rename(p.with_name(prefix p.name))替换空格的脚本天然具备一定的幂等性因为第二次执行时new_name与原来的p.name相同就不会再改。最危险的是编号脚本。第一次运行后文件名已经带上了编号第二次如果直接对全部文件重新编号很容易把之前的顺序破坏。一个简单做法是在编号前先排除已经符合新命名规则的文件files [ p for p in folder.iterdir() if p.is_file() and not p.name.startswith(prefix) ] files.sort(keylambda p: p.name.lower()) for index, p in enumerate(files, start1): new_name f{prefix}{index:04d}{p.suffix} p.rename(p.with_name(new_name))这样第二次运行时带prefix的文件不会被再次处理。但如果你原文件名本身就以prefix开头就要换一种排除方法。最好的办法是不要只靠脚本保护第一次跑之前先备份文件列表或使用干跑日志确认规则无误后再正式执行。7. 常见报错与排查顺序7.1 按这个顺序排查绝大多数文件名问题遇到批量改名报错先不要急着改代码。我喜欢按下面的顺序排查看现象是直接报错还是日志里某几个文件没被处理是改到一半卡住还是改完以后发现命名不对看文件名源文件名是否带扩展名Excel 里的名称是一模一样还是有肉眼看不出来的空格或中文全角字符看目录路径脚本里写的路径是否存在是不是把folder和文件名的反斜杠、正斜杠拼错了看文件状态文件是否被 Word、Excel、WPS、资源管理器某个窗口占用看脚本逻辑新文件名是不是合法目标文件是否已经存在脚本有没有把已经处理过的文件又纳入第二次循环很多问题的根源不在“代码不会写”而是环境或者输入数据没有处理干净。只要你不跳过排查顺序大多数报错都能在三五分钟内定位。7.2 几种高频报错的直接原因报错或现象常见原因FileNotFoundError旧文件名不存在、路径写错、Excel 里的名字和实际文件不一致PermissionError文件正被其它软件打开或当前用户没有目录写权限FileExistsError目标文件已经存在在 Windows 上尤其常见OSError: [WinError 123]新文件名包含非法字符或路径太长中文文件名打印乱码终端编码问题脚本本身不一定错了任务跑到一半卡住大概率是某个文件被占用、目录网络等待或文件数量很大但没有日志反馈PermissionError最常见的诱因是文件被办公软件临时打开。Word 文件如果在桌面上处于打开状态脚本想改文件名时Windows 会拒绝。所以批量执行前先关闭相关软件。中文文件名乱码则要看具体情况。Windows 上的 Python 3 处理 Unicode 文件名本身没有问题多数是终端打印窗口的显示编码不是你预期的。可以不用纠结控制台输出直接看日志文件日志文件用 UTF-8 写入即可。7.3 改完之后的验证步骤改完后不要只看“没有报错”就觉得完事。我一般会做三件事统计一下重命名后的文件数量抽查前面、中间、后面各几个文件看命名规则是否符合预期检查是否存在重复的目标名。数量对比可以用代码renamed_count len(list(folder.glob(*.jpg))) print(jpg 数量:, renamed_count)但这只能看到当前扩展名文件有多少没法直接验证重命名后的名字是否完全正确。更可靠的方法是从日志里挑几十条打开真实目录人工抽查。对最重要的文件建议在改名前先复制一份备份目录或者至少保留重命名日志。后续如果发现规则想调整日志能帮你做反向操作。8. 给新手收尾的一套执行流程8.1 新手先按五步走如果你是第一次用 Python 做批量文件重命名别直接处理几万个文件。把下面五步走完大概率能把风险降下来。第一步在某个临时目录里复制 30 到 50 个有代表性的文件。第二步写一个只针对这个临时目录的脚本先只打印改名计划不执行。第三步检查打印结果看有哪些文件会被改、哪些会被漏掉。第四步在临时目录里真正执行看结果是否和计划一致。第五步确认没问题后再把目录路径从临时目录改成真实目录并且保留日志。这一步看起来很繁琐但对于几万文件的批量任务来说一次误改的成本远高于这几分钟的准备时间。8.2 这几个习惯值得长期保留把常用的安全函数保存成一个公共脚本会让后续工作高效很多。比如safe_rename()、clean_name()、日志记录代码都是可以复用的部分。下次遇到类似需求不需要重写只改文件名生成规则就行。如果涉及 Excel 映射建议把 Excel 表的第一行字段固定下来比如旧文件名、新文件名。长期整理资料时你会发现字段命名混乱比文件命名混乱更让人头疼。同时保持脚本只做一件事要么只是重命名要么只是移动要么只是清理文件名中的特殊字符。把多个任务堆在同一个脚本里虽然看起来“一键完成”但发生错误后很难回滚。单一职责在这里同样适用。8.3 什么时候不该用 Python 改名Python 批量改名并不是万能的。只有几个文件需要简单调整时直接在文件管理器里重命名更快。文件数量中等但规则较复杂时也可以用专门的批量重命名软件图形界面能实时预览。但如果你的文件数量很大、命名规则有明确业务含义、需要反复重跑、或需要先按 Excel 清单对应关系处理Python 脚本的回报就更明显。只要把环境、规则、干跑、日志这几件事做扎实几万个文件的批量重命名并没有想象中那么难。真正踩坑的地方多数不是代码能力而是没有提前发现文件名的重复、非法字符和路径不一致。
返回列表