ARTICLE DETAIL

资讯详情

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

告别手动改名:Python批量重命名与文件夹遍历搜索全攻略

告别手动改名:Python批量重命名与文件夹遍历搜索全攻略 电脑里攒了几年资料、系统镜像、安装包、课件文档的一定懂那种痛苦百度网盘里堆了几千个文件左上角还有个“新建文件夹(3)”“新建文件夹(副本)”下载到本地之后更是彻底失控文件名乱七八糟想找某个版本的工具死活搜不到。真正让人崩溃的是网盘自带的改名功能一次只能处理一个文件鼠标右键点到手酸都整理不完十分之一。这篇文章就来聊聊我自己折腾出来的批量重命名方案一个支持文件夹遍历搜索的本地工具能把整个目录树里的文件一次性扫描出来按自定义规则批量改名解决网盘文件管理和本地归档的终极痛点。适合所有被海量下载文件折磨过的普通用户也适合想给文件管理流程提效的开发者参考。老规矩先泼一盆冷水市面上确实有不少号称能直接改网盘云端文件名的工具但我试了一圈下来要么受限于网盘接口权限要么有账号风控风险改几百个文件就触发验证码得不偿失。所以我这个方案的核心思路是绕开云端落到本地——先把网盘文件批量下载再用本地脚本做文件夹遍历搜索和批量重命名整理完再选择性上传回去。这套流程我跑了两年多改名文件超过一万个踩过的坑基本都在这篇文章里了。1. 网盘文件管理的真实痛点为什么自带的改名功能不顶用很多人觉得文件管理无非就是删一删、改一改名网盘自带的右键菜单完全够用。但一旦文件量级上来比如几百个以“新建文档.docx”命名的文件或者从不同渠道下载、后缀名全是乱码的安装包你才会意识到批量重命名不是锦上添花而是刚需。1.1 从“找文件两小时”到“整理文件一整天”我印象最深的一次经历是整理一个存了三年工作资料的百度网盘账号。里面有项目文档、设计素材、各类软件镜像总量大概四千多个文件。平时下载都是整文件夹拉下来时间一长光“微信图片_20230812104521.jpg”这种无意义文件名就有几百个更别提各种“(1)、(2)、(3)”的副本后缀。用网盘网页端手动改名单个文件至少要操作五步右键、选重命名、等弹窗、输入新名字、按回车。四千个文件就算手速飞快不吃不喝也得大半天。这种机械劳动还特别容易连续操作到脑子发懵一旦改错一个想撤销又是新一轮折磨。后来我明白一个道理凡是重复性高于十次的操作都应该交给脚本去做。1.2 网盘自带批量能力为什么一直没做好百度网盘网页端和客户端的产品设计逻辑重点在“存储”和“分发”对“整理”这个环节投入一直不多。网页端改名一次只能操作一个文件客户端批量选中也只能下载、分享、移动唯独没有批量重命名。这可能跟网盘产品的权限模型有关批量改名涉及大量元数据更新服务端压力不小而且文件被其他设备同步时高频改名会带来同步冲突。我不是说网盘官方永远不做这个功能但至少现在如果你急需整理文件指望官方开发不如自己动手。退一步讲就算未来出了批量改名云端和本地的规则匹配、正则替换、序号填充这些高级功能交给本地脚本处理仍然更灵活。1.3 云端操作和本地脚本到底差在哪我自己做过一个对比同样是整理两百个文件云端手动改名和本地脚本批量处理差距不是一倍两倍而是几十倍云端手动改名平均一个文件10秒两百个要半小时以上还要全程盯屏幕本地脚本批量处理脚本运行三秒完成加上检查规则和干跑预览最多五分钟更重要的是本地脚本可以对文件名做任意变换比如把“xxx【精品】.mp4”里的“【精品】”全部去掉或者在所有章节序号前补零。这种规则在云端界面里基本没法实现。2. 核心需求拆分文件夹遍历搜索与批量重命名的完整链路工欲善其事必先利其器。在写代码之前你得先想清楚这个工具到底要解决哪几件事。我把它拆成了两步第一步是“找到所有该改的文件”第二步是“按规则把名字改对”。两件事看起来简单但各自都有不少值得抠的细节。2.1 文件夹遍历搜索一层一层把家底摸清楚文件夹遍历搜索说白了就是从上到下把整个目录树扫一遍找出所有文件和子文件夹里的文件。这一步是后面所有操作的地基。如果你只处理单层目录那用文件管理器全选就行但要处理“文件夹套文件夹”的多层结构就必须依赖代码。在Python里最常用的是os.walk()它会从你指定的根目录出发递归遍历每一层子目录返回当前的文件夹路径、子文件夹列表和文件列表。我第一版工具就是基于这个函数实现的代码非常轻量import os root_dir D:/downloads for dirpath, dirnames, filenames in os.walk(root_dir): for fname in filenames: full_path os.path.join(dirpath, fname) print(full_path)这段代码跑到任意一个网盘下载目录下能瞬间把整个目录树列出来。如果你对性能有要求也可以用os.scandir()手动维护栈来遍历但对于普通文件整理场景os.walk()已经绰绰有余。遍历搜索有两点必须注意一是隐藏文件夹和系统文件夹比如“$RECYCLE.BIN”、“System Volume Information”这些目录权限特殊盲目遍历可能会报错二是符号链接和快捷方式处理不当容易形成循环引用。我推荐的做法是白名单策略明确只处理普通文件夹和普通文件其他的一律跳过。2.2 重命名规则引擎不只要会替换还要会按模板生成找到了文件之后真正决定生产力的是重命名规则。最简单的场景是字符串替换比如把所有“下载”替换成“资料”。但实际整理网盘文件时更多时候你需要的是模板化命名比如把“2024-01-01 报告.pdf”统一成“2024年01月_报告.pdf”或者给没有规则的图集加上序号。我设计规则时主要用了三类操作字符串替换把旧关键字替换成新关键字处理“【】”、广告后缀、重复空格之类最有效正则表达式替换用re.sub()做模式匹配比如从文件名里提取年份、去掉所有数字、把“_”和“-”统一成同一种分隔符文件名模板生成用占位符组合成新名字比如{keyword}_{date}_{index}.{ext}其中序号由工具自动填充以Python为例正则替换的核心代码长这样import re def apply_rule(filename, pattern, replacement): new_name re.sub(pattern, replacement, filename) return new_name print(apply_rule(test_2024_01_01_final.pdf, r_\d{4}_\d{2}_\d{2}, )) # 输出test_final.pdf这一层规则的灵活程度直接决定了工具的适用范围。我的做法是把规则写进一个配置文件遇到不同场景就套用不同规则集而不是每种需求都改一次代码。2.3 先搜索后改名两步走的自动化工作流很多人在批量重命名上栽跟头都是因为没把“搜索”和“改名”拆成独立阶段。一上来就套规则执行结果目录里哪个文件被改了什么完全没有记录出了问题也没法回滚。推荐的工作流是遍历目录生成完整的文件清单对清单里的每个文件应用规则生成新文件名只展示预览结果不真正执行改名人工确认无误后再批量执行执行完成后输出一份改名日志这个流程看着多了一步预览实际上能帮你避掉90%的失误。我后面会专门讲预览的实现细节。3. 关键实现细节非法字符、重名冲突与目录结构安全如果说遍历和规则是工具的两条腿那边界情况处理就是安全带。很多批量重命名脚本第一版跑得欢一遇真实数据就翻车问题基本都出在下面的几个细节上。3.1 文件名的合法性检查Windows和Linux的规矩不一样不同操作系统的文件名规则差异很大。Windows下不能包含这些字符\ / : * ? |不能以点号或空格结尾不能是保留设备名比如CON、PRN、AUX。Linux相对宽松一些除了/和\0空字符外基本都可以但斜杠还是不能出现。批量重命名最怕的就是生成一个非法文件名在Windows上直接报错中断。所以我加了合法性检查在执行前把所有新名字过一遍筛子import re def is_valid_windows_filename(name): invalid_chars r[\\/:*?|] if re.search(invalid_chars, name): return False if name.endswith( ) or name.endswith(.): return False if name.upper() in [CON, PRN, AUX, NUL, COM1, COM2, COM3, LPT1, LPT2, LPT3]: return False return True3.2 重名冲突处理批量改名时最容易被忽略的雷假设你有一堆文件都叫“文档.pdf”分布在同一个文件夹下批量改名时一不小心就把它们归并成了一个名字操作系统会立刻拒绝第二个改名请求。更隐蔽的情况是A文件和B文件交换名字如果先改A成BB就已经存在整个流程直接崩了。处理重名我有三个策略遇到重名自动追加序号比如“文档(1).pdf”“文档(2).pdf”跳过不改把重名情况记录到日志里事后人工处理两阶段改名先全部改成临时名字再改成最终名字彻底避开交换场景大部分情况下方案1最省心。但有一点要留意追加序号时要检查目标序号是否也被占用了否则“文档(1).pdf”可能撞上本身就存在的文件。3.3 文件名长度与路径深度超过限制会让你措手不及Windows系统对完整路径长度默认限制是260个字符虽然新版Windows 10/11可以通过注册表开启长路径支持但很多程序还是不认。如果网盘下载的目录层级比较深比如“D:/资料/项目A/2024/汇总/五月/图片/”再叠加一个很长的文件名很容易触发路径超限。我的经验是新文件名最好控制在80个字符以内既保险又方便阅读。工具里也加了长度检查超限的文件会单独提示。3.4 目录深度与权限问题网盘下载目录里的隐藏坑用网盘客户端下载文件时有时候会生成一些临时文件或隐藏文件比如.!baiduyun.downloading这种后缀表示文件还在下载中。如果遍历时撞上这种半成品文件直接改名会让下载任务失效。我的处理方式很简单跳过扩展名包含“.downloading”或“!baiduyun”前缀的文件等下载完成后再跑一次整理脚本。另外部分文件夹可能因为权限问题无法改名脚本要捕获异常并且不中断整个流程。try: os.rename(old_path, new_path) except PermissionError as e: print(f跳过权限不足{old_path}) except Exception as e: print(f跳过程{old_path}原因{e})4. 动手实操从环境准备到完整跑通批量重命名理论说了一堆接下来进入实战环节。我用的语言是Python因为它跨平台、上手快、处理文件操作足够稳。如果你更熟悉Node.js或其他语言思路完全一致照着迁移就行。4.1 准备环境Python和必需库的安装系统里装好Python 3.8以上版本然后不需要额外安装任何第三方库标准库里的os、re、sys、datetime就够用了。这样设计有好处换任何一台机器都能直接跑不用折腾依赖。如果你想把规则做成GUI界面可以用Tkinter也是Python自带的库。不过命令行版对我这种“终端党”来说反而效率更高配合argparse模块还能传参数。4.2 核心代码一个支持遍历搜索和批量改名的脚本骨架下面这个脚本是我工具的简化版但核心功能完整指定根目录后自动遍历全部子文件夹对找到的文件套用规则先生成预览再确认执行。import os import re import sys from datetime import datetime def collect_files(root_dir, skip_hiddenTrue): 递归收集所有普通文件路径 collected [] for dirpath, dirnames, filenames in os.walk(root_dir): if skip_hidden: # 过滤隐藏文件夹 dirnames[:] [d for d in dirnames if not d.startswith(.)] for fname in filenames: full_path os.path.join(dirpath, fname) collected.append(full_path) return collected def generate_new_name(filename, modereplace, find, replace, prefix, suffix): 根据模式生成新文件名仅返回文件名部分 stem, ext os.path.splitext(filename) if mode replace: new_stem stem.replace(find, replace) elif mode regex: new_stem re.sub(find, replace, stem) elif mode prefix: new_stem prefix stem elif mode suffix: new_stem stem suffix else: new_stem stem # 清理多余空白 new_stem re.sub(r\s, , new_stem).strip() return new_stem ext def check_conflict(folder, new_name): 检查目标文件夹中是否已存在同名文件 return os.path.exists(os.path.join(folder, new_name)) def main(): root_dir input(请输入要处理的根目录路径).strip() if not os.path.isdir(root_dir): print(目录不存在) sys.exit(1) mode input(选择规则模式replace/regex/prefix/suffix).strip() find input(查找内容replace/regex模式用).strip() replace input(替换为).strip() prefix input(前缀prefix模式用).strip() suffix input(后缀suffix模式用).strip() files collect_files(root_dir) print(f共找到 {len(files)} 个文件) preview_list [] conflict_exists False for idx, old_path in enumerate(files, start1): folder os.path.dirname(old_path) old_name os.path.basename(old_path) new_name generate_new_name(old_name, mode, find, replace, prefix, suffix) if new_name old_name: continue if check_conflict(folder, new_name): print(f[冲突] {old_path} - {new_name}目标已存在) conflict_exists True continue preview_list.append((old_path, os.path.join(folder, new_name))) if not preview_list: print(没有需要改名的文件) return if conflict_exists: print(存在命名冲突建议先解决冲突再执行) return print(\n预览) for old_path, new_path in preview_list[:20]: print(f{os.path.basename(old_path)} {os.path.basename(new_path)}) if len(preview_list) 20: print(f... 共 {len(preview_list)} 条变更) confirm input(\n确认执行(y/n): ).strip().lower() if confirm ! y: print(已取消) return log_lines [] for old_path, new_path in preview_list: try: os.rename(old_path, new_path) log_lines.append(f{old_path} {new_path}) except Exception as e: log_lines.append(f失败 {old_path} {new_path}{e}) print(f改名失败{old_path}原因{e}) log_name frename_log_{datetime.now().strftime(%Y%m%d_%H%M%S)}.txt with open(log_name, w, encodingutf-8) as f: f.write(\n.join(log_lines)) print(f改名完成日志已保存到 {log_name}) if __name__ __main__: main()4.3 先用干跑模式验证规则不要直接执行上面代码里的“预览”步骤本质上就是干跑模式dry-run。我第一次用这个工具时心急直接执行批量改名结果把一组“2023年总结”的文件全改成了“2024年总结”事后才发现规则写错了文件名已经不可逆。从那以后我永远先跑预览核对前二十条结果没问题再执行正式改名。如果你处理的是格外重要的文件建议把预览列表完整导出成文本文件逐条过一遍。4.4 用一个真实案例完整走一遍举个我最近处理的例子从百度网盘下载了一个“设计素材收集”文件夹里面有三层子目录上百个文件名是“未标题-1.png”“未标题-2.png”这种完全没法用。我选择“replace”模式把“未标题-”替换成“素材_”顺便在最终确认前加了一个序号填充逻辑。这一步看似简单但如果你在同一个文件夹下有“素材_1.png”和“素材_2.png”替换后没有冲突如果原始文件里恰好有一张已经叫“素材_1.png”就会触发重名检测脚本会提示冲突这样就能避免“未标题-1.png”改名后覆盖掉原来那张图片。整个过程不到一分钟效果非常直观。5. 最容易翻车的几个坑以及我的应对经验批量重命名工具写出来容易真正用得顺手却要踩过几次坑才知道哪里要加固。下面这几个问题我基本都遇到过也整理成了对应的规避方案希望能帮你少走弯路。5.1 不可见字符和全角半角符号有些文件名表面看起来是空格其实是全角空格或者夹着\u00a0这种不间断空格。用str.replace( , _)根本替换不掉正则里写\s倒是能匹配但容易误伤。我建议做一步预处理把所有全角符号转成半角把不间断空格替换成普通空格。类似的情况还有文件名里带#、%、在网页端下载时看起来没问题到了本地命令行处理时偶尔会被当成特殊字符处理正则时也要留意转义。5.2 网盘同步目录里的“假路径陷阱”很多人用百度网盘客户端时开启了“同步空间”本地有一个专门同步文件夹。这种情况下千万不要直接在同步目录里批量重命名。客户端会实时监控文件变化批量改名会触发海量同步请求很容易导致同步冲突甚至让客户端卡死。我的做法是先在非同步目录里用本地工具整理出最终版本再把整理后的文件移入同步空间。如果你确实需要整理同步目录里的文件建议先退出客户端改完名再登录让客户端重新建立索引。5.3 长路径和超长文件名前面提过Windows路径上限260字符实际在网盘下载场景更容易触发因为网盘目录名本身可能就带路径片段。比如“我的资源/2024/项目交付/版本更新/最终版/”这种层级随便一个文件名一拼接就超长。我设置了一个硬性阈值新文件名不超过100个字符。超过的在预览阶段就标红提醒。这个阈值看起来保守但在Windows上绝对安全。如果确实有超长命名的需求可以在注册表里开启长路径支持但我不建议因为很多第三方工具不认。5.4 没有保留原始文件名映射表批量重命名最恐怖的场景不是改错而是改完之后你根本不知道原来是什么名字。所以每次执行改名我都强制输出一份日志内容包含改名前和改名后的完整路径。这份日志既是回滚依据也是追溯凭证。如果条件允许强烈建议在改名工具里加一个“撤销”功能。实现思路也不复杂用日志里的信息反向执行一遍os.rename(new_path, old_path)。虽然不能覆盖所有手工修改但至少能应对纯脚本操作的撤销。5.5 文件被占用导致的改名失败Windows上非常常见的情况是某个文件正被Word、Excel或图片查看器占用改名的时候会提示“另一个程序正在使用此文件”。遇到这种脚本必须优雅处理不能一报错就中断整个任务。我采用的方式是捕获异常后把失败项写入单独的空文件夹脚本继续往后跑。等全部执行完再根据失败日志逐个排查那些占用文件。6. 把这个工具升级成你的私人文件管理助手基础版脚本能用之后我陆续给它加了不少功能现在它已经不只是一个重命名工具更像一个个人文件管理系统。如果你也有同样的需求可以顺着下面几个方向扩展。6.1 用规则配置文件替代硬编码把规则写死在脚本里换台电脑或者换一批文件就要改代码太低效了。我后来把规则抽成了JSON配置文件里面可以定义多组规则脚本按顺序执行。{ rules: [ {action: replace, find: 【精品】, replace: }, {action: regex, find: \\(\\d\\)$, replace: }, {action: prefix, prefix: 整理_}, {action: suffix, suffix: _已整理} ] }加载配置后脚本会自动逐条套用规则。遇到不同的整理场景我只需要切换配置不需要改代码。6.2 按文件类型自动分流归档批量重命名只是整理的第一步接下来通常还要把文件移动到对应的分类目录里。比如图片放“images”、文档放“docs”、压缩包放“archives”。这个逻辑可以做成文件扩展名映射表在改名的同时完成移动。要小心的是移动和改名叠加时风险系数更高千万别省预览步骤。6.3 加入重复文件识别能力网盘下载最烦人的是什么同一个文件在不同文件夹里出现了好几次大小一样、内容一样但名字不一样。批量重命名不解决这个问题但可以在改名后做个辅助判断比如按文件大小加哈希值计算唯一标识找出重复项。Python里可以用hashlib.md5逐块读取文件内容计算哈希几万个文件也能接受。不过这个功能计算量大建议在批改结束后单独运行。6.4 延伸到本地其他存储设备的整理这套工具本质是“遍历目录 应用规则 批量改名”完全不限于百度网盘下载的文件。U盘、移动硬盘、照片导出目录、开发项目里的资源文件夹通通可以用同一套逻辑。我现在的习惯是任何设备里的文件整理都先丢进这个脚本跑一遍预览看看会变成什么样再决定执行与否。它已经成了我文件管理流程里最顺手的一环。最后分享一个小技巧配一个固定快捷键或把脚本加入右键菜单。我用的是Windows计划任务加自定义右键菜单项在任何文件夹上右键选“扫描并重命名”终端窗口直接弹出输入规则就完事。这套折腾下来再也不用面对“新建文件夹(8)”这种名字了。
返回列表