资讯动态

MATLAB批量重命名文件:从dir到movefile的完整实战指南

发布时间:2026/10/16 20:45:09 来源:尧图企业网站定制
用MATLAB做批量重命名这事儿第一次听起来可能有点冷门但一旦你需要给几百个文件统一改名字就会觉得真香。我先说个实际场景项目收尾要归档数据文件夹里两百多张实验截图命名全是Figure_1、untitled_3这种平台要求统一改成日期_项目代号_三位序号。手动一个个改不现实Windows文件管理器的多选重命名又只能加前缀和序号不能把旧名字清掉。我当时的数据本来就在MATLAB里顺手写了个循环十几行代码半分钟收工。这篇文章就把这套思路完整拆开从最底层的dir和movefile两个函数讲起再到加前缀、改扩展名、替换关键字、正则规则、处理子文件夹这些实际场景最后附上我踩过的坑和一个能直接拿去用的通用批量重命名函数。1. 批量重命名的核心思路其实很简单1.1 任何语言做这件事都是同样的四步批量重命名听起来像是文件管理器的活但本质就是四步跟用什么工具没关系先是拿到文件清单然后一条条遍历接着算出每个文件的新名字最后把旧文件变成新文件。区别只在于这四步分别用什么手段完成。在MATLAB里四步的推荐搭配我直接用实际经验给你列出来拿清单用dir遍历用for循环算新名字用fileparts、strrep、regexprep、sprintf按需组合执行改名用movefile有人会问MATLAB里没有rename这种函数吗严格说没有针对文件的重命名专用内置函数但换个角度想一下就通了重命名的本质就是把一个文件在同一个目录里从旧名字变成新名字这不就是一次移动操作吗所以movefile这个用于移动文件的神器就成了最顺手的改名工具。这也是这套方案最关键的一个思维转换。多说一句很多教程会让人用system命令去调用操作系统自己的ren或mv那样也能行但跨平台兼容性差返回信息的可读性也差。所以我个人优先用纯MATLAB函数只有在极端大批量的场景才会考虑系统命令这一点后面会专门展开。1.2 为什么拿MATLAB来干这个活先说明我不是说所有批量重命名都应该用MATLAB。文件数量少、规则也简单直接用操作系统自带的资源和第三方小工具可能更快。但如果碰到下面任意一种情况MATLAB的优势就很明显命名规则比较复杂比如把第3到第8个字符抽出来重新拼成新名字根据修改时间生成日期前缀把文件夹里所有包含特定关键字的文件按某种顺序重新编号。这种规则在图形界面工具里常常无从下手在MATLAB里只是几行表达式的事。重命名需要纳入现有工作流。比如数据分析和可视化本来就在MATLAB里跑完一批图顺便重命名归档不需要切到别的软件。规则可能会改。脚本里改一个变量重新跑一次就行比在图形界面里重新勾选几百个文件省事得多。我做了个直观对比方案规则灵活度跨平台适合场景系统自带多选重命名低只能加前缀和序号仅当前系统简单、数量少第三方批量重命名工具中等通常限当前系统桌面文件批处理MATLAB脚本dirmovefile高可用函数句柄和正则全平台规则复杂、数量大、嵌入流程所以这个方案不是用来替代所有重命名工具的而是在规则复杂追求可重复避免反复手动操作这几个诉求下最顺手的一条路。2. 认识两个核心函数dir和movefile2.1 dir文件清单全靠它dir返回的是一个结构体数组。每次调用返回结果里的每个元素就代表目录下的一个条目常用字段如下字段含义name文件名不含路径folder文件所在文件夹的完整路径bytes文件大小单位字节isdir逻辑值1表示文件夹0表示文件datenum / datetime修改日期调用方式上有两个细节必须注意。第一个dir(folder)会返回当前目录下的所有条目包括表示当前目录的.和上一级的..新手经常踩这个坑。所以在实际脚本里我一般会写成dir(fullfile(folder, *.jpg))这样的形式让dir只返回匹配文件名模式的文件这样.和..就自动不在结果里了省事很多。第二个dir返回的文件名只有名字部分不含路径。你要做的是把文件所在目录和文件名重新拼起来这时候一定不要自己用字符串拼接[folder \ name]这种方式因为Windows用反斜杠、Linux和Mac用正斜杠不同系统下会出问题。老老实实用fullfile它能自动适配当前系统的路径分隔符。2.2 movefile改名的本质是一次移动movefile是MATLAB里移动文件和文件夹的函数最基本的用法是这样movefile(D:\data\old.txt, D:\data\new.txt);源路径和目标路径在同一个目录下的时候这个操作的效果就是重命名。说得再直白一点任何重命名在文件系统层面都是从一个名字移动到另一个名字movefile正好把这个动作完整暴露出来了。movefile还有一个可选参数f作用是允许覆盖只读属性文件。但这个参数要谨慎用后面讲坑的时候会专门提到——绝大多数情况下的数据丢失不是因为有只读文件挡路而恰恰是默认的同名文件直接覆盖行为。另外movefile有两个返回值[ok, msg] movefile(oldFile, newFile);ok为1表示成功为0表示失败msg是失败时的错误信息。在批量循环里我强烈建议用这种带返回值的写法即使某个文件失败了循环也能继续跑下去做完之后统一看哪些失败了比一个文件报错就中断整个批处理要舒服得多。2.3 第一版脚本跑通把一个思路落成代码最朴素的第一版是这样的folder pwd; % 换成你自己的目录 files dir(fullfile(folder, *.jpg)); for k 1:length(files) oldFile fullfile(folder, files(k).name); newFile fullfile(folder, [backup_ files(k).name]); [ok, msg] movefile(oldFile, newFile); if ~ok warning(msg); end end这段脚本把当前文件夹下所有jpg文件统一加上backup_前缀。你可以先在某个测试文件夹里放两个文件跑一遍确认效果没问题再换成正式目录。其实整个批量重命名就是从这个几句话的小循环扩散开来的——后面所有看似复杂的场景都是在算新名字这一步上做文章。需要提醒一件事脚本一旦跑起来旧文件名就没了而且movefile没有undo机制。所以第一版务必放在测试目录里试跑这一点我后面还会反复强调。3. 从能跑到好用三个高频场景3.1 批量加前缀加前缀恐怕是出现频率最高的需求。实验数据归档、给素材打标签、给一批图片加系列编号都是一个套路。folder D:\experiment\result; prefix 20250402_归档标记_; files dir(fullfile(folder, *.png)); for k 1:length(files) oldFile fullfile(folder, files(k).name); newFile fullfile(folder, [prefix files(k).name]); movefile(oldFile, newFile); end注意prefix变量是写死的你也可以改成用sprintf生成带序号的prefix sprintf(20250402_%02d_, k)。这样每条文件的前缀里还能带上序号归档的时候看一眼文件名就知道它在处理流程里的顺序。如果担心k和旧文件顺序对不上先对files做一次排序再跑排序问题我在第5节会专门讲。3.2 批量改扩展名另一个高频场景是把一批文件的扩展名统一修改。比如平台只收jpg不收png或者之前导出时格式选错了。用fileparts把文件名拆成主名扩展名然后重组files dir(fullfile(folder, *.png)); for k 1:length(files) [~, name] fileparts(files(k).name); oldFile fullfile(folder, files(k).name); newFile fullfile(folder, [name .jpg]); movefile(oldFile, newFile); endfileparts函数有三个常见输出参数路径、主文件名、扩展名。这里我只需要主文件名所以前面写了~来忽略路径。用[name .jpg]拼接新扩展名比用正则去替换更直接因为fileparts已经把原来的扩展名剥掉了不会发生误替换文件名中间某个点和字符的情况。改扩展名这件事要小心把png改成jpg并不会真的让图片格式转换只是文件名后缀变了文件内容还是PNG编码。如果下游工具严格按照扩展名判断格式可能还是会出现读不了或显示异常的情况。这种需求真正要做的是格式转换那就得用imread加imwrite了。文件名层面的批量修改只是名义上改后缀两者别混为一谈。3.3 批量替换文件名中的关键字第三种最常见就是把一批文件里的某个关键字换成另一个。这里分为字面替换和正则替换两档先讲字面的。files dir(fullfile(folder, *)); for k 1:length(files) if files(k).isdir continue end oldName files(k).name; newName strrep(oldName, 旧项目号, 新项目号); if strcmp(oldName, newName) continue end movefile(fullfile(folder, oldName), fullfile(folder, newName)); endstrrep是纯文本替换不认特殊符号。比如文件名叫data.1.txt想替换成data.2.txt直接strrep(oldName, data.1.txt, data.2.txt)即可不会把.当成特殊字符。很多人一开始用regexprep反而会踩正则的坑所以我的建议是能字面说明白的需求一律用strrep确实需要模式匹配的再上正则。这段代码里还用到了files(k).isdir判断这是为了跳过文件夹只处理文件。4. 进阶玩法正则替换和子目录递归4.1 正则表达式替换打开规则的大门当规则从某一段字符换成另一段变成某种模式换成另一种模式时就该regexprep上场了。举一个我实际处理过的例子。一批数据文件叫data.2023.raw.png、data.2023.processed.png这种需要把年份从2023批量改成2024。新手很容易写成这样newName regexprep(oldName, .2023., .2024.); % 错误写法这里的.在正则里代表任意一个字符所以表达式.2023.会匹配任意字符 2023 任意字符结果就是它不光匹配到了年份还可能把前后不该动的字符也替换掉甚至可能匹配到完全不相干的位置。正确写法是给点号加反斜杠转义newName regexprep(oldName, \.2023\., .2024.);再复杂一点的例子想统一把文件名里的日期格式从20230405改成2023-04-05用正则也能完成但定位和替换的复杂度会明显上升。我的建议是别在正则里堆太复杂的表达式MATLAB正则可以在命令行里反复实验先拿两三个样例文件名试到准确为止再批量执行。每一个正则表达式在正式跑之前都值得花两分钟验证一下否则误伤一批文件你会非常后悔。4.2 用**扫描所有子目录实际归档时文件不会老老实实躺在一个文件夹里更多的场景是散落在多级子目录中。MATLAB从R2016b开始dir支持**这个路径模式一个通配符就能递归匹配多层子目录files dir(fullfile(root, **, *.jpg));比如root下面有实验1/正常组、实验1/异常组、实验2这些子目录上面一行就能把所有这些目录下的jpg全部找出来。而且返回结果里的folder字段会对应到每个文件实际所在的子目录路径重命名的时候用fullfile(files(k).folder, files(k).name)拼路径不会弄错位置。如果你的MATLAB版本比较老**用不了需要自己写递归。核心逻辑其实不难先在函数内部处理当前目录再对每个子目录调用自身function batchRenameRecursive(folder, prefix) files dir(fullfile(folder, *.jpg)); for k 1:length(files) movefile(fullfile(folder, files(k).name), ... fullfile(folder, [prefix files(k).name])); end subDirs dir(folder); for k 1:length(subDirs) if subDirs(k).isdir ~ismember(subDirs(k).name, {., ..}) batchRenameRecursive(fullfile(folder, subDirs(k).name), prefix); end end end递归版本有个好处处理规则想扩展也容易比如可以只处理某个文件名模式的子集也可以对每个子目录带上不同的前缀。不过日常用**已经足够递归函数可以作为版本兼容的备选方案存着。4.3 封装一个通用的批量重命名函数学到这里每次写循环其实蛮烦的而且循环体和算新名字的代码混在一起规则复杂一点就会很乱。更好的做法是封装一个通用函数把遍历和执行固定下来只留命名规则给使用者去定义。我最终沉淀下来的函数是这样的function okCount batchRename(folder, pattern, nameRule) % folder : 目标文件夹例如 D:\data % pattern : 文件匹配模式例如 *.jpg % nameRule : 函数句柄输入旧文件名返回新文件名 items dir(fullfile(folder, pattern)); okCount 0; for k 1:length(items) if items(k).isdir continue end oldName items(k).name; newName nameRule(oldName); if isempty(newName) || strcmp(oldName, newName) continue end [ok, msg] movefile(fullfile(folder, oldName), ... fullfile(folder, newName)); if ok okCount okCount 1; else warning(重命名失败: %s - %s, 原因: %s, oldName, newName, msg); end end endnameRule是一个函数句柄你只需要定义给旧名字返回新名字的规则剩下的遍历、拼路径、错误处理交给函数统一做。调用方式非常直白% 统一加前缀 batchRename(pwd, *.jpg, (n) [归档_ n]); % 把扩展名从 png 改成 jpg batchRename(pwd, *.png, (n) [n(1:end-4) .jpg]); % 替换关键字 batchRename(pwd, *, (n) strrep(n, 旧, 新));一个小细节n(1:end-4)字符串切片时我假设文件名末尾是4个字符的扩展名.png所以去掉最后4个字符。如果你的文件名或扩展名长度不确定就先用fileparts拆一下再拼那样更稳。这个函数我自己的项目里用了很久每次碰到批量重命名需求都是先改一行nameRule再跑一次结果很稳定。5. 常见坑与排查方法实录5.1 文件名的排序和我们想的不一样dir返回的文件列表是按字典序排列的不是自然排序。什么是字典序就是image_10.jpg会排在image_2.jpg前面因为字符串比较的时候到第三个字符开始逐位比较1小于2所以10排在2前面。你想按数字顺序给文件编序号直接拿dir的顺序来用就错了。解决思路是提取文件名里的数字按数字排序files dir(fullfile(folder, *.jpg)); nums zeros(length(files), 1); for k 1:length(files) token regexp(files(k).name, \d, once, match); if isempty(token) nums(k) inf; else nums(k) str2double(token); end end [~, idx] sort(nums); files files(idx);这是一个朴素的数字排序能解决大多数编号需求。如果文件名里有多个数字或者数字位数不固定这个写法就不够用更稳妥的办法是找一个支持自然排序的现成工具函数或者在排序之前先统一改名的前缀规则让文件名本身变得更有规律。我自己的习惯是如果最终要给文件重新编号先按修改时间排序再依据当前顺序生成三位序号这样跟处理先后的直觉一致。5.2 同名文件会被静默覆盖这是最容易丢数据的地方前面提到过movefile在目标文件已存在、且目标文件不是只读的情况下会直接覆盖而且不报错。这是个非常隐蔽的坑。比如你有report_2023.pdf和report_2024.pdf两个文件批量改成final_report.pdf后者就会悄悄把前者覆盖掉数据找不回来。我在封装batchRename时故意加了一步新老名字完全相同时就跳过。但这只能避免重复改名造成的自我覆盖真正的同名覆盖还得自己在命名规则里规避。执行前最稳妥的做法是先检查目标是否存在existingNames {files.name}; for k 1:length(files) newName nameRule(files(k).name); if isempty(newName) || strcmp(newName, files(k).name) || ... ismember(newName, existingNames) continue end % 到这里说明新名字没有冲突可以执行 movefile 了 end其中ismember(newName, existingNames)就是检查目标名字是否已经被列表里的某个文件占用。虽然执行时仍有竞态风险但单线程顺序执行时这个检查已经能挡住绝大多数误覆盖。5.3 文件被其他程序占用就是改不动Windows下如果一个文件正被编辑器、看图软件、Office等程序打开着movefile通常拿它没辙会报类似文件被占用无法访问这类错误。这种情况不是脚本逻辑问题纯粹是文件被锁住了。排查思路很简单先看报错信息里是哪个文件把它在打开它的程序里关掉然后重新跑脚本。批量循环中用了[ok, msg] movefile(...)这种写法的话单个文件失败不会中断整个任务最后检查输出记录把失败的那几个单独处理即可。我试过在重命名之前把所有会占用文件的软件都关掉成功率会提高不少这属于操作习惯上的细节。5.4 中文文件名在旧版本可能乱码如果你用的MATLAB版本比较老在Windows系统上处理中文文件名有时会看到一串意义不明的乱码这是因为文件系统返回的编码和MATLAB内部字符编码不一致。老版本对这块的支持一直不算好。解决建议依次是能升级就升级不能升级的话尽量避免在脚本里直接拼中文可以改用通配符加英文规则匹配实在要处理中文文件名先单独打一段调试代码看看dir返回的名字到底是什么再决定怎么适配。新版本里中文文件名读写基本稳定我这两年在较新的环境里处理过带中文的归档文件没有遇到乱码。5.5 必不可少的先预览再执行最后一条与其说是坑不如说是习惯任何批量重命名脚本正式执行前先跑一遍只打印不执行的预览模式。for k 1:length(items) if items(k).isdir continue end oldName items(k).name; newName nameRule(oldName); if ~strcmp(oldName, newName) fprintf(%s - %s\n, oldName, newName); end end就这几行值得每次都跑一遍。它不会花多少时间但能让你在执行前看到完整的新旧对应关系。我的经验是有七成左右的命名问题在预览阶段就能一眼发现比如新名字里有空格、后缀重复、某几个文件没匹配上规则。别嫌这步麻烦它比改错之后再想办法恢复要划算得多。6. 实操心得从能用变成好用6.1 动手之前的三件事这几条是我自己吃了亏之后养成的习惯不管多急的重命名需求我都不会跳过。第一备份。把要批量的整个文件夹复制一份到临时目录再操作。文件数量不大时直接复制就行文件很大时至少把命名规则最复杂的文件单独备份一份。movefile没有内置撤销机制别迷信应该没问题这句话。第二小范围试跑。正式执行之前先用dir确认匹配到了哪些文件再拉出前三个文件做一遍预览。这一步可以和备份穿插进行先在备份目录里跑第一版脚本确认没问题再去正式目录跑第二版。第三记录规则。在脚本开头注释写清楚这次重命名做了什么比如把2023替换成2024范围是data文件夹下所有raw图像。归档类的活过几个月回头看有注释能省下大量回忆成本。6.2 文件特别多的时候怎么提速movefile本质是一次一次调用系统文件操作几千个文件可能就要好几秒甚至更久。如果文件数量到了上万级别或者你在处理大量小文件可以考虑绕开movefile直接调用系统命令。Windows上可以用rensystem([ren fullfile(folder, oldName) newName ]);需要提醒ren的旧路径可以带完整路径但新文件名不能带路径也就是说新名字只能是文件名。Linux和Mac系统是mv两个参数都可以带完整路径system([mv fullfile(folder, oldName) fullfile(folder, newName) ]);用system的代价是跨平台代码不通用字符串拼接时路径里有空格也容易出错我加了一对双引号来规避空格问题。所以我的建议是几千个文件以内直接用movefile稳定、跨平台、报错信息友好到了万级规模再考虑系统命令。另外循环里每调一次system都要启动一个新的系统进程其实也有开销更彻底的提速是把所有改名命令写进一个批处理脚本一次性执行但那样出错后排查反而麻烦我就不推荐了。6.3 还能扩展出哪些玩法批量重命名这个能力本身很小但它能嵌到更多流程里。比如根据文件的修改时间生成新名字。dir返回结果里有datenum或datetime字段用datetime(files(k).datenum, ConvertFrom, datenum)拿到时间对象再格式化成yyyyMMdd_HHmmss拼进文件名。这样归档时不需要打开每个文件看属性就能知道它们的大致产生时间非常实用。再比如结合表格的映射关系。如果有一张表存着旧文件名到新文件名的对应关系可以在MATLAB里用readtable读进来然后遍历文件列表到表里查新名字查不到就跳过。这种玩法对交接类的重命名任务特别管用规则是别人给定的你只要负责执行。还有我后来做的一个改动把batchRename函数放进了自己的个人工具箱启动MATLAB时自动加载。每次收到重命名需求只要写好nameRule那一行剩下的全部交给函数。这个函数处理过的文件数量可观出了问题的次数很少而且问题基本都是规则本身写错了在预览阶段就已经发现。再提一个我自己的小习惯命名规则里尽量少用中文。不是歧视中文文件名而是跨平台、跨版本、跨编码环境下中文文件名始终是那个可能出问题不好排查的点。能用字母、数字、下划线表达清楚意思就尽量用归档文件会省心很多。如果实在需要中文描述建议单独维护一个对照说明文件而不是把中文直接写死在文件名里。批量重命名这事本身不大但做对做错差别很大。规则明确、先预览、再加一层备份基本不会翻车。我个人处理了大量文件之后最大的体会是越是看起来小的自动化脚本越值得把边界条件想清楚。下次你面对几百个乱糟糟的文件名时不妨让MATLAB试试。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑