☰
Python批量重命名文件:5分钟写脚本告别手动改名
2026/9/26 6:32:27 网站建设 项目流程

告别手动改文件名!5分钟写个Python脚本,批量搞定所有文件重命名

先说一下我自己的经历。前阵子帮朋友整理一个摄影项目,相机导出来的素材全是IMG_0234.jpg、IMG_0235.jpg这种名字,完全看不出内容。几百个文件要按拍摄日期、地点、序号重新命名,一个个手动改?改到一半就想砸电脑。后来我花五分钟写了个 Python 脚本,把整个文件夹的文件一次性处理完,朋友当场愣住:“这活儿你平时都靠这个?”从那以后,批量文件重命名就成了我处理素材、整理下载目录、归档项目文件时最常用的一个小工具。

今天这篇文章就是来分享这个方法的。不管你是完全没写过代码的小白,还是已经会一点 Python 但没系统整理过文件操作的朋友,看完都能自己动手写一个顺手的小脚本。我们会从最基础的需求拆解开始,讲到os模块和pathlib的用法,再给出一套可以直接抄走的完整代码,最后还会分享我踩过的坑和排查经验。整体写下来你会发现,批量重命名这件事,真没必要手动一个个来。

1. 批量重命名背后的核心需求与解决思路

1.1 为什么手动改名让人抓狂

手动重命名的痛点,干过的人都有体会。文件一多,光是“选中、右键、重命名、输入、回车”这一套动作就要重复几百次,手指累不说,脑子更容易乱。更麻烦的是,很多时候命名规则不是简单地加个序号,而是要把日期、地点、项目名、类别等信息拼进去。比如你有一批合同扫描件,希望文件名变成合同_2025-03月_供应商A_01.pdf,手动操作就特别容易出错:

  • 序号敲错,两个文件重名,系统直接拒绝。
  • 日期填错,事后想按文件名排序就全乱了。
  • 改到一半忘记改到哪了,前后编号不一致,整个文件夹看起来乱七八糟。

我曾经试过用系统自带的“全选后重命名”功能,Windows 会给所有文件加上文件名 (1)、文件名 (2)这种格式。但问题是,它不能自由组合日期、分类、原文件名这些信息,而且处理完的文件名还是没什么辨识度,基本等于没解决问题。

1.2 用 Python 解决的核心思路

Python 解决这个问题的思路其实很清晰:用代码读取文件夹里的所有文件名,按照定义好的规则生成新文件名,然后执行重命名操作。整个过程分四步:

  1. 定位目标文件夹。
  2. 获取文件夹里所有文件的列表。
  3. 对每个文件名做解析和转换,生成新名字。
  4. 调用系统重命名接口,把旧名字换成新名字。

这套思路的优势在于,规则一旦定好,执行就是稳定、可复现的。不管文件是 10 个还是 1000 个,脚本执行的时间差不了太多。而且因为规则是写出来的,你可以在真正重命名之前先“预演”一遍,把新旧文件名对照表打印出来检查,确认无误后再真正动手。

说穿了,这就是用一段确定的逻辑替代重复的手工操作。和 Excel 里用公式批量处理数据是一个道理——先定义规则,再一次性应用,而不是一个个单元格去改。

1.3 选 Python 而不选其他方案的原因

可能有人会问,Windows 自带的重命名工具、第三方批量改名软件不是也能做吗?为什么非要 Python?

我的看法是:第三方软件确实方便,但有两个局限。一是规则定制能力有限,复杂规则往往要付费版才开放;二是没法“沉淀”下来。你用鼠标点出来的规则,下次换一批文件,可能又要重新配置一遍。而脚本是文本文件,可以保存、复用、修改。我自己的习惯是,把常用脚本按场景分类存到一个文件夹里,遇到“整理照片”“清理下载目录”“归档合同”就对应跑一个,参数改一下就行,效率完全是另一回事。

Python 在这个场景里还有个隐藏优势:生态。你今天是批量重命名,明天可能就要按 EXIF 信息整理照片,后天要把文件名提取的信息写入 Excel。这些需求 Python 都能无缝衔接,因为你用的是同一套语言和思维模式。

2. 动手前必须掌握的两个核心模块

2.1os模块:Python 操作文件的老牌主力

要说批量重命名,os模块是绕不开的基础。它提供的功能很直接:读写文件属性、创建目录、列举目录内容、重命名文件等。最常用的几个函数是:

  • os.listdir(path):列出指定目录下所有文件和子目录的名字,返回一个列表。
  • os.rename(old_name, new_name):把旧文件名改成新文件名。
  • os.path.splitext(filename):把文件名拆成“主名”和“扩展名”两部分。
  • os.path.join(path1, path2):把目录路径和文件名拼成完整路径,自动处理分隔符。
  • os.path.isfile(path):判断路径对应的是不是文件。

举个例子感受一下。假设我们要把一个叫pic1.jpg的文件重命名为旅行_01.jpg:

import os old_name = "pic1.jpg" new_name = "旅行_01.jpg" os.rename(old_name, new_name)

就这么简单。但注意,os.rename只能处理两个名字,不能自动加序号、不能批量。所以我们的脚本要做的,就是用一个循环把文件夹里每个文件都执行一次这个操作。

2.2pathlib模块:更现代、更省心的文件路径处理

如果你是新学 Python,我建议你直接从pathlib入手。这是 Python 3.4 以后加入的标准库,把路径当成对象来操作,整体体验比os.path拼字符串舒服得多。

同一件事用pathlib写是这种感觉:

from pathlib import Path folder = Path("D:/照片/2025年3月") for file_path in folder.iterdir(): if file_path.is_file(): print(file_path.name) # 文件名,不含路径 print(file_path.stem) # 主名,不含扩展名 print(file_path.suffix) # 扩展名,比如 .jpg print(file_path.parent) # 所在目录

iterdir()直接遍历目录,is_file()判断是不是文件,.name拿文件名,.stem拿主名,.suffix拿后缀。没有一堆字符串拼接,逻辑清楚很多。

我个人的建议是,日常脚本用pathlib写,读起来比os舒服;但如果你维护的是老项目,里面全是os.path,那就跟着现有代码风格走,不要混用。两种方式都能完成任务,关键是别让自己糊涂。

2.3 老手常用的几个路径细节

不管用哪个模块,有几个细节是刚接触文件操作的人经常忽略的:

  • Windows 路径建议用Path("D:/素材")这种正斜杠写法,或者直接在路径字符串前加r变成原始字符串,比如r"D:\素材"。否则反斜杠\n会被解析成换行符,踩坑概率极高。
  • 如果你想让脚本在任意电脑上都能跑,最好在脚本开头用input()让用户输入文件夹路径,或者用Path.home()获取用户主目录,不要在代码里写死一个路径。
  • 处理完一批文件后,如果需要检查结果,可以再用folder.iterdir()把新文件名打印出来看一遍,确认没有重名、没有奇怪字符。

3. 从零写一个足够通用的批量重命名脚本

3.1 先说清楚目标场景

我这里设计的脚本,解决的是最常见的三种需求:

  • 给文件加统一前缀,比如所有素材文件前面加上项目名。
  • 给文件按顺序加编号,比如001、002、003。
  • 用原文件的修改日期拼进新文件名,比如20250315_001.jpg。

这三种场景覆盖了绝大多数个人整理文件的需求。你不需要一次写一个完美无缺的“万能脚本”,只要能解决眼前的问题,再留一点扩展空间,就够了。

3.2 完整代码可以直接抄走

下面这个脚本我日常在用,改动不大。主要有两个模式:加前缀、加日期前缀加编号。

from pathlib import Path from datetime import datetime def batch_rename(folder_path, mode="prefix", prefix="", start_num=1): """ 批量重命名脚本,支持两种模式: - prefix: 在原名前面加前缀,例如 项目A_旅行照片.jpg - date_number: 用文件修改日期 + 序号作为新文件名,例如 20250315_001.jpg """ folder = Path(folder_path) if not folder.exists(): print(f"目录不存在:{folder_path}") return files = [f for f in folder.iterdir() if f.is_file()] if not files: print("该目录下没有找到任何文件。") return # 先把文件按名称排序,保证编号顺序稳定 files.sort(key=lambda x: x.name.lower()) print("以下文件将被重命名:") rename_pairs = [] for index, file_path in enumerate(files, start=start_num): if mode == "prefix": new_name = f"{prefix}{file_path.name}" elif mode == "date_number": mtime = file_path.stat().st_mtime date_part = datetime.fromtimestamp(mtime).strftime("%Y%m%d") suffix = file_path.suffix.lower() new_name = f"{date_part}_{index:03d}{suffix}" else: print(f"未知模式:{mode}") return new_path = folder / new_name rename_pairs.append((file_path, new_path)) for old_path, new_path in rename_pairs: print(f"{old_path.name} -> {new_path.name}") confirm = input("确认执行重命名?输入 y 确认,直接回车取消:") if confirm.strip().lower() == "y": for old_path, new_path in rename_pairs: if old_path.resolve() == new_path.resolve(): continue if new_path.exists(): print(f"跳过:{new_path.name} 已存在,无法覆盖。") continue old_path.rename(new_path) print(f"已重命名:{old_path.name} -> {new_path.name}") else: print("已取消,未做任何修改。")

3.3 脚本里的关键设计,逐个解释

这段代码看起来不长,但里面有几个细节,恰好是容易出问题的点。

第一个是排序。遍历文件之前,我先把文件列表按文件名排序了。这样做的好处是,编号出来的顺序是稳定可预期的,不会一会儿是 A 文件在前面,一会儿变成了 C 文件。如果你不排序,iterdir()返回顺序由文件系统决定,在不同机器上可能完全不一样,那编号就会乱。

第二个是重名保护。脚本在真正执行重命名之前,会检查new_path是否已经存在,如果存在就跳过。这一步很重要,因为两个文件改完变成同一个名字,系统会直接报错或者覆盖,文件就找不回来了。宁可这次跳过,也比丢失文件强。

第三个是确认机制。我先打印出所有旧名字到新名字的对应关系,让用户输入y确认后才动手。这和“先在草稿上检查一遍再誊写”是一个道理。批量操作最大的风险就是改完后悔,所以多一道确认,值得。

第四是日期处理。file_path.stat().st_mtime拿到的是 Unix 时间戳,我再用datetime.fromtimestamp()转成可读日期,然后格式化成年月日。这样输出的文件名像20250315_001.jpg,一看就知道是什么时候的文件。

3.4 实际运行效果长什么样

假设我有个文件夹叫D:/照片/三月素材,里面有这些文件:

风景1.jpg 风景2.jpg 家人的合影.png 随手拍.jpg

在命令行里运行脚本,选择date_number模式,执行效果大概是:

风景1.jpg -> 20250310_001.jpg 风景2.jpg -> 20250310_002.jpg 家人的合影.png -> 20250314_003.png 随手拍.jpg -> 20250315_004.jpg 确认执行重命名?输入 y 确认,直接回车取消:y 已重命名:风景1.jpg -> 20250310_001.jpg 已重命名:风景2.jpg -> 20250310_002.jpg 已重命名:家人的合影.png -> 20250314_003.png 已重命名:随手拍.jpg -> 20250315_004.jpg

如果选prefix模式,结果会更直观:

风景1.jpg -> 旅行计划_风景1.jpg 风景2.jpg -> 旅行计划_风景2.jpg 家人的合影.png -> 旅行计划_家人的合影.png 随手拍.jpg -> 旅行计划_随手拍.jpg

这样一来,文件名一下子就统一了,按名字排序也比之前有规律得多。

4. 把原文件名“翻译”成新文件名的高级玩法

4.1 一个真实场景:把中文名转成拼音文件名

有次我需要把一批中文命名的课程资料上传到某个老旧的档案系统,对方系统不支持中文文件名,全部乱码。手动一个个翻译又要疯了。这时候脚本的优势就出来了:我们可以调用拼音库,把中文名转成拼音再拼接成新文件名。

依赖库装一下就行:

pip install pypinyin

核心逻辑很简单:

from pypinyin import lazy_pinyin def to_pinyin(name): return "_".join(lazy_pinyin(name)) old_name = "高等数学第一章.pdf" new_name = to_pinyin(old_name) print(new_name) # gao_deng_shu_xue_di_yi_zhang.pdf

如果你想在文件名里保留原来的信息,也可以拼起来,比如高等数学第一章_gao_deng.pdf,这样人眼能看懂,系统也不会乱码。

这个思路可以延伸很多:英文名转大写、空格替换成下划线、去掉特殊符号、日期格式统一等。本质上都是“对原文件名做字符串处理”,规则自己定,脚本就是执行规则的工具。

4.2 用原文件信息生成更智能的文件名

除了纯字符串翻译,我们还可以读取文件的元数据来生成新名字。常见的元数据包括:

  • 修改时间:file_path.stat().st_mtime
  • 创建时间:Windows 上可以用st_ctime,但注意在不同系统上含义不一样
  • 文件大小:file_path.stat().st_size
  • 图片的拍摄时间:通过PIL库读取 EXIF 信息

有一次我给相机导出的照片归档,就是用读取 EXIF 拍摄时间的方式,按日期重组了文件夹结构,文件名也改成拍摄时间的格式。这样导出的照片直接传云盘,按文件名排序就是时间排序,找照片快了很多。

from PIL import Image from PIL.ExifTags import TAGS def get_photo_date(file_path): try: img = Image.open(file_path) exif = img.getexif() if exif: for tag_id, value in exif.items(): tag_name = TAGS.get(tag_id, tag_id) if tag_name == "DateTimeOriginal": return str(value).replace(":", "").replace(" ", "_") except Exception: pass return None

这样读出来的文件名可能是20250315_142530_001.jpg,精确到了秒。这个方法比依赖文件修改时间更靠谱,因为修图软件保存文件时,修改时间可能被覆盖,但 EXIF 里的拍摄时间不会被改动。

4.3 批量重命名多个文件夹里的文件

有时候文件不只有一个文件夹,而是按月份分了多个目录。逐个目录跑脚本太麻烦了,我们可以再套一层循环,遍历所有子目录:

from pathlib import Path root = Path("D:/项目归档") for folder in root.iterdir(): if folder.is_dir(): batch_rename(folder, mode="prefix", prefix="归档_")

这样一层一层处理下去,几十个文件夹几分钟就能搞定。这也是脚本复用价值最明显的地方:规则定义一次,应用到所有目录。

5. 常见问题与排查技巧实录

5.1 问题一:提示文件找不到或者名称错误

很多新手遇到的第一个报错就是FileNotFoundError。多半原因不是文件不存在,而是路径没写对。特别是 Windows 下直接复制出来的路径,常常自带反斜杠,Python 里会被解析成转义字符。

解决办法很简单,用Path对象而不是字符串:

from pathlib import Path folder = Path("D:/项目归档/2025年3月")

如果是从命令行复制路径,看到的是D:\项目归档\2025年3月,直接改成上面的写法就行。要么用原始字符串:Path(r"D:\项目归档\2025年3月")。

5.2 问题二:重命名后文件跑到别处去了

有次我用os.rename(old_name, new_name),传的路径一个是绝对路径,一个是相对路径,结果文件被移到了当前工作目录,找了好久。这个问题的根源是路径基准不一致。

建议所有操作都基于同一个 Path 对象来处理,比如都用folder / old_name和folder / new_name,不要一会儿用相对路径一会儿用绝对路径。最简单的方式是,脚本里所有文件路径都由那个folder变量派生出来。

5.3 问题三:文件名里带点导致扩展名丢了

有的文件名本身包含多个点,比如2025.03.15 风景.jpg。如果直接用split(".")[0]取主名,只会保留第一个点前面的部分,后面的就全乱了。

正确做法是用pathlib的.stem和.suffix,它会自动把最后一个点当成扩展名分隔符:

name = "2025.03.15 风景.jpg" p = Path(name) print(p.stem) # 2025.03.15 风景 print(p.suffix) # .jpg

别自己手工切分文件名,规则太多很容易出错。

5.4 问题四:执行到一半发现规则错了

这时候如果你是直接跑的脚本,很可能已经改了一批文件,改错的文件名字就乱了。所以我会在脚本里加一个“预演”功能:先打印所有新旧对照,不执行真正的重命名。确认无误后再手动输入确认符执行。

你也可以在脚本最前面加一个dry_run变量,默认设成True,等确认无误再改成False运行。这样可以把“看效果”和“真正执行”分开,安全很多。

5.5 问题五:只想处理特定类型的文件

有时候一个文件夹里有图片、文档、压缩包,我只想重命名 jpg 文件,其他文件不要动。过滤条件很简单:

files = [f for f in folder.iterdir() if f.is_file() and f.suffix.lower() == ".jpg"]

也可以过滤包含某些关键字的文件:

files = [f for f in folder.iterdir() if "临时" in f.name]

这个能帮你避开那些不需要动的系统文件、隐藏文件、备份文件。

5.6 问题六:PowerShell 或命令行运行 Python 时报错

运行脚本时不熟悉命令行,会出现类似“无法将 xxx 项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,或者提示 python 命令找不到。这个通常不是脚本的问题,而是 Python 没装好,或者没加到系统环境变量里。

解决思路:

  • 先确认 Python 装没装。在 PowerShell 或命令行里敲python --version,有版本号说明装好了。
  • 如果提示找不到,就重新安装 Python,安装时记得勾选Add Python to PATH。
  • 安装好之后,在目标文件夹里打开命令行,输入python 脚本名.py就能跑。

如果你嫌命令行麻烦,也可以用 VS Code 打开文件夹,在编辑器里直接运行脚本。下载 VS Code 后装一个 Python 扩展,打开.py文件点右上角三角形运行就行,对新手友好很多。

6. 我的实操心得和使用建议

6.1 重命名前先想清楚命名规则

写脚本本身五分钟就够了,真正花时间的是想清楚“新文件名应该长什么样”。我一般会先手动改三五个文件,把规则定型,再写脚本套用到全部文件。比如我整理照片时,会先确定格式是日期_序号.jpg,然后想清楚“日期取拍摄日还是修改日”,这两者选错了,后面整个文件夹都会乱。

定规则的时候,建议也考虑排序问题。文件管理器排序通常按字符顺序,所以如果希望按时间排序,文件名开头最好就是日期,而且是YYYYMMDD这种格式。不要用03月15日,因为排序时你会发现 10 月排在 2 月前面,根本对不上。

6.2 重要文件先备份,永远不要嫌麻烦

批量重命名是“不可撤销”的操作。系统没有回收站给文件夹里的人看操作记录,一旦改错,想靠手工找回难度极大。所以我哪怕脚本写得再熟,面对重要文件夹,也一定先复制一份备份到临时目录。等确认脚本结果没问题,再删掉备份。

特别是涉及照片、合同、论文这些没有第二份的数据,备份是底线。这条经验是踩了坑才总结出来的。

6.3 把这套脚本沉淀成你自己的工具箱

我自己电脑里有一个scripts目录,专门放这些实用小脚本。每个脚本开头我都写了注释,说明这个脚本是干嘛的、参数怎么改、适用于什么场景。碰到类似需求,直接复制改个目录路径就能用,五分钟都不用。

建议大家也建立这个习惯。脚本的价值不在于一次跑完,而在于下次遇到类似问题时,你可以不用重新想思路,直接把它拿出来改造。慢慢地,你会发现自己处理文件越来越快,也越来越少做重复劳动。

6.4 从重命名开始,进入自动化的世界

批量重命名是很小的一件事,但它背后体现的思维方式是可以迁移的:凡是重复三次以上的操作,都值得把它脚本化。整理桌面、清洗重复文件同步目录、批量改图片尺寸、下载网页里的资源……这些都可以用 Python 逐步自动化。

一开始不用想太多,就先从今天这个小脚本开始。找到你电脑里那个乱糟糟的文件夹,定一个命名规则,敲几行代码,跑一遍,你会立刻感受到“编写工具”和“使用工具”之间的差距。这种掌握感,一旦尝到就回不去了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询