尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

用Python批量重命名文件:从入门到自动化实战

发布时间:2026/9/26 6:32:08

资讯中心
01
ARTICLE

用Python批量重命名文件:从入门到自动化实战

用Python批量重命名文件:从入门到自动化实战
从相机导出的照片还是IMG_4231.JPG这种名字下载的合同全部叫“新建文档(5).pdf”项目周报攒了一整年的“汇报PPT-最终版-真最终版.pptx”——这种时刻所有人脑子里都会闪同一个念头怎么就不能一次全改掉手动改名不仅慢还特别容易在改到第50个文件时手一抖把序号敲重复了然后整个整理计划全部作废。其实这个问题的解法很简单就是写一个Python脚本用os模块里的几个内置函数批量搞定所有文件重命名。整个过程熟练的话5分钟内能跑通就算对着教程一步步来半小时内也足够落地一个能实际用的工具。这篇文章就是把整个思路和代码拆开揉碎了讲清楚怎么设计重命名规则、怎么写最基本的改名脚本、怎么应对带序号、按日期、批量替换这类进阶需求以及实际操作中那些文档里不会写但迟早会踩的坑。适合完全没写过Python的小白也适合有一定基础、想快速把自己的文件整理脚本写得规范一点的读者。1. 批量文件重命名这件事5分钟脚本到底解决了什么问题先别急着装Python想清楚你为什么要做这件事脚本怎么写才有意义。1.1 手动改名的两个绕不开的死穴文件重命名看起来是最简单的操作按F2、敲名字、回车三步就完事。但“简单”和“适合批量做”是两码事。手动改名有两个致命问题一个是效率天花板另一个是错误率。效率方面假设你手上有200张照片需要按“日期_序号”重新命名敲200次文件名每次光输入和核对就按秒算20分钟起步。这还只是文件名短的情况要是名字里带日期、地点、项目编号这些字段输入量直接翻倍。更难受的是这种操作是纯重复劳动做完一轮手都酸了脑子也木了。错误率方面更反直觉越简单重复的操作人越容易走神就越容易出错。我见过同事整理投标文件手动把“技术标-v3.docx”改成“技术标-final.docx”结果手滑改成了“技术标-finla.docx”文件发出去了才发现。这种错误在批量操作里更高发因为人在连续重复操作时注意力是递减的改到后半程基本是机械动作序号跳一位这种事完全察觉不到。那用脚本解决这两个问题天然就是正解机器不会累不会跳序号执行速度按毫秒算。写一次脚本以后每次整理文件都能复用换个文件夹改个参数就能跑。1.2 现成的批量改名工具不好用吗肯定会有人问网上不是有一堆批量重命名软件吗为什么还要自己写Python脚本我试过好几款这类工具确实能干活但痛点也很明确。免费工具限制多要么限制单次处理文件数量要么在导出结果时强制加水印要么界面里全是广告。付费工具不划算为一个偶尔才用一次的功能掏几十上百块绝大多数人都会犹豫。规则写死、不灵活图形化工具的规则通常是“加前缀/后缀、替换文字、加序号”这种固定组合想实现“把文件名中间的日期提取出来并重新格式化”这种定制规则连门都找不到。公司电脑装不了这可能是最现实的问题办公电脑软件安装权限管得严随便装第三方小工具容易被信息部门拦下来。反过来看Python脚本完全绕开这些限制开源、免费、不依赖图形界面、规则完全自己定。只要是能跑Python的电脑就能用哪怕公司电脑装不了Python也可以用打包工具把脚本转成exe文件双击即用。这笔账算下来写脚本的5分钟成本几乎可以忽略。1.3 为什么选Python而不是其他语言这个问题我被人问过很多次我的回答很直接因为Python在这件事上是“零基础友好”和“功能够用”的最佳交集。批处理脚本这件事理论上Shell脚本、批处理bat、甚至Node.js都能做但它们各有各的门槛。Shell脚本在Windows上默认跑不了bat写起来语法太古旧Node.js还得先装运行时。Python不一样装好就能用语法像半英语半数学的自然语言逻辑也直白。更关键的是Python自带了一整套处理文件和目录的标准库——os、glob、pathlib、re。这些库不用安装任何第三方依赖装了Python就都有。这意味着“批量重命名”这个需求用Python写不需要考虑依赖管理、环境冲突之类的复杂问题脚本本身也就是几十行代码的事。做一个类比其他方案像是为了开个罐头去买了整套工具箱Python则是手里正好有一把好用的开罐器。2. 写脚本前的准备工作和设计思路动手写代码前先花两分钟把环境和规则想清楚这能让你少走一半弯路。2.1 Python环境搭建别在这一步卡住Python本身是免费开源的直接去官网下载对应系统的安装包即可。Windows用户有两条路可选一是用微软应用商店的Python二是用官网安装包。官方安装包有一个几乎所有教程都会强调但新手容易忽略的细节安装向导第一步务必勾选Add Python to PATH。这个选项如果不勾后续在命令行里输入python会提示“不是内部或外部命令”很多初学者就在这一步被劝退了。勾选之后打开命令行输入python直接进入交互界面就可以写代码了。从实用角度说我不建议新手一上来就去折腾IDE。写这个批量重命名的脚本系统自带的IDLE就完全够用或者装一个VS Code配合Python插件也行但这两个都是后话——直接找一个能编辑.py文件的编辑器保存后命令行里运行就已经是完整的工作流了。VS Code主要是写长脚本、调试时更舒服对这个需求来说不是必需品。装好后可以做一个快速验证命令行输入python看到版本号说明成功。再输入几行最简单的print语句试一下这就算跑通了。2.2 重命名规则的提前设计先问自己三个问题写脚本之前先把需求拆清楚。做技术的人有个共识规则越清楚代码越简单。我把重命名需求拆成三个维度改哪些文件是当前目录下所有文件还是某种特定类型是只改文件名不改扩展名还是连扩展名一起改放大缩小范围脚本的逻辑完全不同。改成什么格式改成纯序号还是前缀加序号还是保留原有部分再加新内容新名字里需要哪些信息日期、项目名、类别规则的一致性所有文件用同一套规则还是需要根据文件类型分别处理比如图片用日期命名文档用前缀加日期命名。举个具体例子假设你要整理一个项目的所有设计稿规则是“项目名_类别_序号”。那么你至少要明确项目名是什么、类别怎么分按文件夹按原文件名关键词、序号从1还是从001开始。这些问题想清楚了代码就是按图索骥。2.3 核心工具Python标准库里的三个主力批量重命名绕不开三个模块都是Python自带的不用额外安装。os最基础的文件操作库listdir用来列目录rename用来改名join和path用于拼路径。在早期的脚本里os是绝对主力。pathlibPython 3.4以后引入的面向对象路径库用起来比os更顺手用Path对象代替字符串拼路径代码读起来直观很多。re正则表达式库用来做复杂的字符串匹配和替换。比如从一串文件名里抽出日期、截取特定字段、判断是否符合某种模式全靠它。这三个库在文本里会反复用到我先在这里打个底后续代码里看到不熟的函数可以随时回来看这一段。3. 循序渐进写代码从一行改名到批量处理代码这事上来就甩一大段会把人劝退。我按难度分成四个阶梯每一级都能独立运行越往后越接近真实场景。3.1 第一级先用单文件改名跑通流程初次接触先别管批量把一个文件改名这个动作搞定。假设当前目录下有个文件叫“old_name.txt”要改成“new_name.txt”代码长这样import os old_name old_name.txt new_name new_name.txt os.rename(old_name, new_name) print(改名完成)这段代码里os.rename就是核心操作第一个参数是原文件名第二个是新文件名。运行之后当前目录下的old_name.txt就变成了new_name.txt。这样做的意义在于理解这个核心API的行为。这里有个铺垫性细节待会批量时也会遇到os.rename在执行时如果new_name已经存在程序会直接报错中止。意识到这一点很重要因为批量处理时这种情况会经常碰到比如序号撞车、文件名冲突。后面的进阶脚本里会专门写逻辑来处理。单文件跑通后试着把路径换成完整路径C:/Users/xxx/Desktop/old_name.txt。注意Python里路径可以用正斜杠Windows资源管理器里看到的反斜杠在这里不用转义成双写正斜杠最省心避免踩反斜杠转义的地雷。3.2 第二级批量改一个目录里的全部文件好现在把范围扩大到整个目录。假设你要把D盘某文件夹里所有文件的文件名前面加上前缀“backup_”这个脚本可以直接抄import os folder_path D:/test_files/ # 改成你自己的目标文件夹路径 prefix backup_ for filename in os.listdir(folder_path): old_path os.path.join(folder_path, filename) # 拼出完整旧路径 new_name prefix filename # 生成新文件名 new_path os.path.join(folder_path, new_name) # 拼出完整新路径 os.rename(old_path, new_path) # 执行改名 print(f已改名: {filename} - {new_name})这段代码是批量重命名的地基三个细节逐个说明。os.listdir(folder_path)拿到文件夹下的所有文件和子目录名注意是纯文件名不包含路径。要操作文件得自己拼完整路径这就是os.path.join存在的意义。直接用os.rename(filename, new_name)在命令行里看似可以但在脚本里如果不拼绝对路径实际改的是“当前工作目录”下的文件不是你目标文件夹里的文件运行结果就是文件根本没变或者直接报错找不到文件。os.path.join就是一个拼接工具它自动处理操作系统路径分隔符。你在Windows上写D:/test_files它知道后面拼出来的结构是D:/test_files/backup_test.txt。这个函数在某些简单案例里看似多余但实际项目中离开它路径处理早晚出幺蛾子。os.rename在Windows上有个细节如果目标文件已经存在它会报FileExistsError而不是静默覆盖。这对我们来说是好事至少误覆盖不会悄无声息发生。这个脚本跑一遍目录下所有文件名都会加上“backup_”前缀。想换成后缀把new_name prefix filename换成new_name filename.split(.)[0] _backup 原扩展名这种思路稍后会在综合案例里给出更完整的写法。3.3 第三级加序号和类型过滤让脚本更聪明只有固定的前缀后缀还远远谈不上“智能”。真实需求通常长这样“把文件夹里所有.jpg图片统一命名成photo_001.jpg、photo_002.jpg这种格式。”这就涉及两件事过滤文件类型和补位编号。import os folder_path D:/photos/ count 1 for filename in os.listdir(folder_path): # 只处理.jpg文件其他一律跳过 if not filename.lower().endswith(.jpg): continue old_path os.path.join(folder_path, filename) # 序号补零让编号宽度一致方便排序 new_name fphoto_{count:03d}.jpg new_path os.path.join(folder_path, new_name) os.rename(old_path, new_path) print(f已改名: {filename} - {new_name}) count 1代码里有两个容易被忽略但很关键的点。一个是filename.lower().endswith(.jpg)。这里加了lower()是因为Windows文件扩展名不区分大小写文件可能是.JPG、.Jpg、.jpeg各种写法统一转小写再判断不会被扩展名大小写坑到。另一个是count的更新位置。仔细看continue的时候count不增加只有实际改名成功才加1。这样能保证编号是连续的没有中间跳号。如果把count 1放在循环最开始一旦遇到一个非jpg文件序号就会空一个出来的文件编号就不连续了。这种逻辑细节平时感觉不到等出来的文件名编号断档时才追悔莫及。这里说的命名用到了Python的f-string格式化{count:03d}的意思是“把这个整数按三位数展示不足位前面补0”。改成05d就是五位补零文件多的时候用得上。3.4 第四级用pathlib写出更现代更省心的代码前三级用的都是os这是最经典也最通用的写法。但Python 3.4之后引入了pathlib操作路径的方式更面向对象代码也更简洁。我现在的习惯是新脚本优先用pathlib这里给一个等价的实现from pathlib import Path folder Path(D:/photos/) count 1 # 用glob过滤文件*代表任意文件名.jpg是后缀 for file in folder.glob(*.jpg): new_name fphoto_{count:03d}{file.suffix} # file.suffix拿到扩展名 file.rename(folder / new_name) # 直接用 / 拼接路径 print(f已改名: {file.name} - {new_name}) count 1也就几行代码短了接近一半。拆解一下它做了哪些事。Path是路径对象folder / new_name这种写法直接拼接路径比os.path.join更直觉几乎就是数学公式。glob(*.jpg)直接按模式匹配文件匹配成功的就是目标文件不需要手动判断扩展名。file.suffix能拿到文件扩展名file.name拿到完整文件名取起来比字符串切割优雅得多。file.rename()直接对Path对象调用底层还是调os.rename但对使用者来说少写不少参数。这段代码没有做编号续接和错误处理先不塞太多内容下一节综合案例里会一并加全。4. 一个完整的综合案例把照片文件夹整理成“日期_序号”来一个能直接覆盖大部分场景的综合案例。假设你的手机照片导到电脑后全是IMG_20250101_123456.jpg这种格式你想整理成“2025-01-01_001.jpg”这种按日期分组的格式同一天的从001开始编号。这种需求在真实生活里非常高频拍娃的、拍猫的、做项目留档的都会遇到。先分析一下需求再写代码。文件名里的日期其实已经藏在IMG_20250101_123456.jpg里了从第4位开始取8位数字就是日期串20250101。这里用字符串切片filename[4:12]就能拿日期或者用正则表达式re.search(r(\d{8}), filename)提取。我推荐后者抗干扰能力更强因为有些文件是IMG_2025-01-01_123456.jpg规则不一样。下面这个脚本的思路是遍历文件夹里所有.jpg文件提取日期创建“日期_序号”的新名字同时处理日期相同文件的序号递增最后执行改名。import os import re from collections import defaultdict folder_path D:/photos_output/ counters defaultdict(int) # 记录每个日期下已改名的数量 for filename in os.listdir(folder_path): # 只处理图片文件跳过其他类型 if not filename.lower().endswith((.jpg, .jpeg, .png)): continue # 用正则在文件名中提取8位数字作为日期 match re.search(r(\d{8}), filename) if not match: print(f跳过未找到日期: {filename}) continue date_str match.group(1) # 20250101 formatted_date f{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]} counters[formatted_date] 1 # 同一天计数加1 seq counters[formatted_date] new_name f{formatted_date}_{seq:03d}.jpg old_path os.path.join(folder_path, filename) new_path os.path.join(folder_path, new_name) try: os.rename(old_path, new_path) print(f已改名: {filename} - {new_name}) except FileExistsError: print(f跳过目标已存在: {filename} - {new_name})这段代码有几个值得反复咀嚼的设计。counters用defaultdict(int)来维护每个日期已改名的数量每次遇到同一个日期就序号加1。这是解决“同一天多张照片递增编号”的标准手段换成普通字典就要先判断键是否存在代码会繁琐不少。用了tuple传入endswith方法endswith可以一次判断多个后缀不用写三个or。re.search在找不到匹配时返回None所以先判断再继续避免程序崩溃。这在实际运行时非常关键因为文件夹里大概率有一些无关文件比如.mov视频或者.ini配置文件它们的文件名里可能没有日期。遇到FileExistsError就打印跳过而不是直接崩溃这是批量操作的基本素养。万一有文件已经按这个规则命名过了脚本可以继续跑完不用人工介入重来。这个脚本输出的新名字是2025-01-01_001.jpg这种格式按名称排序时同一天的照片会自然聚在一起而且顺序就是拍摄的后台序号查找非常方便。我实际用这个脚本整理过上万张照片效果非常稳。5. 那些年踩过的坑批量重命名常见问题排查实录代码能跑是一回事跑得“不炸”是另一回事。这几个坑我基本都在正式场合踩过每一个都值得单独写一笔。5.1 常见报错和文件系统限制速查表报错信息或异常现象原因解决方案FileNotFoundError源文件路径写错或文件名拼写不对先打印old_path确认路径正确用os.path.exists验证出口FileExistsError目标位置已有同名文件加try/except捕获或提前用os.path.exists判断PermissionError文件被占用通常是Word、Excel这类程序正打开着关闭占用程序后重新运行或者在脚本里跳过该文件文件名过长Windows路径文件名总长度超过260字符缩短新文件名或改用短路径目录文件“消失”可能在子文件夹里listdir只扫一层改用os.walk递归扫描子目录或确认目标文件不在深层目录中文乱码控制台编码问题通常Windows下用GBK显示UTF-8文件名会乱脚本开头加# -- coding: utf-8 --或调整终端编码到UTF-8大小写不敏感Windows上Abc.txt和abc.txt是同一个文件改名时可能出现“覆盖”提前清理同名不同大小写的文件或在规则中统一小写这个表是我把常见问题按优先级捋出来的实际遇到最多的还是文件占用和文件名冲突两个几乎每次批量运行时都至少撞上一个。5.2 文件占用最容易被忽略的隐形杀手有一次我帮同事整理一堆Excel报表为了验证脚本就在他打开着Excel的文件夹里跑结果在大概第30个文件时程序被PermissionError中断了提示某个文件正被另一个进程使用。原因就是同事正打开着其中一张表。遇到这种情况常规做法是关闭Excel再重跑但更健壮的脚本会“带病运行”在异常处理里单独捕获PermissionError跳过该文件并输出一句提示让其他文件继续改名。try: os.rename(old_path, new_path) except PermissionError: print(f文件被占用跳过: {filename}) except FileExistsError: print(f目标已存在跳过: {filename})多写一个异常分支省掉一整轮人工核对的时间。批量操作天然就该具备一点容错能力毕竟你不能保证文件夹里所有文件都在“可控状态”。5.3 序号断档和排序错乱一个隐藏需求的真实案例很多人在改完名之后发现文件夹按“名称排序”并不是自己想象的样子。比如你命名了photo_1到photo_100按名称排序时photo_10会排在photo_2前面因为字符串排序是逐位比的1比2小所以10排在2前面。这个问题的标准解法就是前面代码里的补零用三位、四位、五位数来保证统一位长但这引出一个新问题你提前不知道文件总数是多少。我经常建议先跑一遍os.listdir数一下文件数量再决定补几位。文件数量是几十个的话三位就够是几百个最好用四位简单估算就行。file_count sum(1 for f in os.listdir(folder_path) if f.endswith(.jpg)) digits len(str(file_count)) # 由文件总数量决定补位长度这段小逻辑在脚本里很实用动态决定补位宽度不用回头改代码。5.4 递归子文件夹只改一层还是全盘扫荡前面所有代码用的都是os.listdir或Path.glob这两个都只处理一层目录。如果你的文件散落在多级子文件夹里——比如“D:/素材/2024年/1月/文件名.xlsx”这种结构——那么你需要在脚本里用os.walk或Path.rglob做递归遍历。from pathlib import Path for file in Path(D:/素材).rglob(*.pdf): print(f找到: {file})rglob就是递归glob它会遍历所有子目录。但注意递归处理时务必确认路径是对的改名逻辑也要再检查一遍别把子目录里的相对路径搞混。我给一个简单建议除非你明确知道需要递归否则先按单层处理真需要了再改多一层递归Bug概率翻一倍。6. 把脚本打磨成顺手工具命令行参数和容错设计脚本写好了但每次都要改代码里的路径再运行用不了几次就烦了。让脚本接受命令行参数是更优雅的做法一行命令直接指定目标和规则不用开编辑器改代码。6.1 用sys.argv接受外部参数Python里sys.argv能拿命令行传入的参数第0个是脚本名字后面的是实际参数。比如运行python rename.py D:/photos --prefix holiday脚本就能从argv里取到路径和前缀。这个技巧特别适合把脚本当成“自定义工具”用。我把常用的整理脚本固定下来后就再也没打开过代码编辑器去改路径直接在命令行里敲python rename.py D:/photo --type jpg --pattern IMG_ --replace holiday_代码大致长这样import sys import os def main(): if len(sys.argv) 2: print(用法: python rename.py 文件夹路径 --prefix 前缀) sys.exit(1) folder_path sys.argv[1] prefix if --prefix in sys.argv: idx sys.argv.index(--prefix) prefix sys.argv[idx 1] for filename in os.listdir(folder_path): old_path os.path.join(folder_path, filename) new_name prefix filename new_path os.path.join(folder_path, new_name) os.rename(old_path, new_path) print(f已改名: {filename} - {new_name}) if __name__ __main__: main()这里用ifname main包住主逻辑是标准做法保证脚本既能被命令行直接运行也能被其他脚本import进来复用。参数解析的实现方式虽然离一个完整的argparse还差得远但对个人工具完全够用。6.2 永远先试运行再真跑这是我想重点强调的实践心得任何批量修改文件的脚本第一遍永远只打印不改名。在脚本里增加一个dry_run开关默认试运行模式把即将执行的改名操作全部打印出来一眼扫过去确认没问题再改成正式模式跑。dry_run True # 改成False后正式执行 if dry_run: print(f[试运行] {filename} - {new_name}) else: os.rename(old_path, new_path)这个开关看着不起眼但实际价值巨大。批量改名是覆水难收的操作虽然可以再改回来但几百个文件的名字如果规则设计错了恢复原状的成本极高。试运行模式让我在正式跑之前发现了很多规则漏洞比如提取日期的正则写错位、序号规则顺序不对都是靠先打印一版发现后改掉的。我的经验是第一版脚本写完后至少跑两遍试运行第一遍检查单文件名产出是否正确第二遍快速扫一遍是否所有文件都覆盖到。确认无误后再置为False正式执行这样基本不会翻车。6.3 保留“改名日志”事后还能追溯脚本跑完后可以顺手导出一个改名映射表把所有旧文件名和新文件名按行写入一个CSV文件。这个文件平时放着没用但一旦发现某个文件改名后找不到了或者想还原部分文件它就是唯一的查找依据。import csv log_rows [] # 在循环里把 (旧名, 新名) 追加进 log_rows with open(rename_log.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([旧文件名, 新文件名]) writer.writerows(log_rows)文件名里有中文时encoding参数用utf-8-sig而不是utf-8因为utf-8-sig会让Excel直接正确打开CSV不乱码普通utf-8编码的中文CSV在Excel里很容易乱。这个小细节也是在处理过一批中文名文件后踩出来的。7. 写在最后一个实用小技巧最后分享一个让脚本更耐用的习惯把常用规则写成“配置区”放在脚本文件头部每次使用只改配置不改逻辑。我现在做的文件整理脚本开头必定是一段大注释里面列出默认路径、前缀后缀、是否递归、试运行还是正式运行这样即使隔了半年再回来看这个脚本也不会忘记每个参数是干嘛的。脚本的具体逻辑也许过段时间就看不太懂了但配置区永远一目了然。这个思路其实大大降低了脚本的“生锈”速度也是个人脚本和一次性脚本的本质区别。批量文件重命名这个需求说大可大说小可小但养成“写规则前先确认范围、写代码时先试后跑、跑完后留个日志”这三个习惯它能省下的时间远比写那五分钟多得多。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。