资讯动态

PowerShell批量重命名MP4文件:正则提取歌手歌曲名实战

发布时间:2026/10/14 15:31:33 来源:尧图企业网站定制
1. 需求拆解与方案选型一个播放列表文件夹引发的整理工程先说点实在的。如果你手头有一大批MP4文件文件名长这样——“歌手A - 歌曲名一.mp4”“歌手B - 歌曲名二.mp4”而它们全都堆在一个叫“Beautiful Chinese Music Selected Playlist”的文件夹里当你看着播放器里乱七八糟的标题列表、想着以后怎么按歌手快速检索时你就知道这次不能再手动一个个改了。这个场景的核心需求其实有三个批量提取、规则重命名、不破坏文件。所谓“提取歌手名和歌曲名”指的就是从MP4文件名本身解析出“歌手”和“歌曲”两个信息字段然后按统一的命名规则重新组织文件名比如统一成“歌手 - 歌曲名.mp4”或者反过来。这里的关键前提是文件名里已经包含了歌手和歌曲信息只是格式不规范或者被各种下载工具加上了多余前缀后缀比如“[www.example.com]”“_HD”之类导致播放器显示混乱。那问题来了为什么不用现成的批量重命名工具说实话市面上有不少图形化批量改名工具像某知名文件管理器自带的重命名工具、各种免费批量改名软件都能做查找替换、加序号这类操作。但这类工具在处理“拆分字段后重新组合”的需求时往往很别扭有的不支持正则有的正则支持得很蹩脚有的重命名几百个文件时试运行预览和实际结果不一致。更关键的是它们很少能让你灵活定义“从文件名中提取哪几段、再按什么顺序拼回去”这样的逻辑。我自己用下来的结论是这种结构化提取 重命名的任务用脚本才是最顺手的。脚本可以选择Python也可以选择PowerShell。之所以我这次选了PowerShell是因为它在Windows环境下的几个实打实的优点系统自带不需要安装Python解释器也不需要处理pip依赖。对中文文件名的支持很稳配合正则处理UTF-8/UTF-16文件名都正常。Get-ChildItem配合Rename-Item可以直接对文件对象操作不需要频繁拼接路径。出错时能拿到对象级别的异常信息排查方便。还要澄清一点这个“PS”指的是PowerShell不是Photoshop。我看到这个标题时第一反应也愣了一下但做批量文件重命名这件事用PhotoShop纯属拿大炮打蚊子PowerShell才是正解。如果你手头正好有一批从音乐软件、素材站或朋友那收集来的MP4音乐文件文件名格式五花八门那这篇文章的脚本逻辑可以直接抄改一改文件夹路径和正则规则就能用。2. 核心逻辑拆解正则提取与命名规则的设计思路2.1 文件名模式分析先弄清楚你的输入长什么样在写任何代码之前第一步永远不是写代码而是先手动看20个文件名。这一步我吃了不少亏曾经以为文件名格式很统一结果跑了两次批量改名最后发现有一批文件根本没匹配上白折腾。以“Beautiful Chinese Music Selected Playlist”这类文件夹为例我实际遇到的典型文件名模式大致有这几种歌手A - 歌曲名一.mp4标准模式中间有空格加连字符歌手A-歌曲名一.mp4没有空格直接连字符歌手B_歌曲名二.mp4下划线分隔【歌手C】歌曲名三.mp4中文方括号包裹歌手名歌手D - 歌曲名四 (Official Music Video).mp4带多余后缀标签未知歌手 - 歌曲名五 1080p.mp4带清晰度标记如果文件名来源比较杂乱甚至还会出现“歌曲名 - 歌手.mp4”这种反向排列的情况。所以命名规则设计的第一步就是确定你的输入格式到底是什么。最简单的做法是跑一段扫描脚本把目录下所有文件名打印出来人工过一遍归纳出共性。这一步决定了你的正则能不能一次匹配90%以上的文件。我在这个项目里的做法是先把所有文件列出来手动扫了一遍。发现大约85%的文件都是“歌手 - 歌曲名.mp4”这种标准模式剩下的要么是多了标签后缀要么是分隔符不统一。这个统计很重要因为它决定了我后续是写一套正则通吃还是写两套正则以备兼容。2.2 正则表达式怎么写提取字段的细节与陷阱确定了输入格式是“歌手 - 歌曲名”之后核心就是一个正则表达式。PowerShell里正则匹配用的是-match运算符结果存放在自动变量$matches里。一个典型的基础正则长这样$pattern ^(.*?)\s*-\s*(.*?)\.mp4$其中^(.*?)是非贪婪匹配尽量少地匹配字符\s*-\s*表示连字符前后可以有空格也可以没有(.*?)\.mp4$匹配歌曲名直到扩展名结束。比如文件名“歌手A - 歌曲名一.mp4”这个正则提取到的$matches[1]是“歌手A”$matches[2]是“歌曲名一”。但注意一个陷阱(.*?)这种非贪婪写法在PowerShell的-match里是默认从左到右匹配的一旦遇到不符合规则的字符就可能导致误提取。比如文件名“歌手A - 歌曲名一 (Live).mp4”在歌曲名位置会提取出“歌曲名一 (Live)”这个结果本身没错但后处理时需要决定是否去掉括号里的演出标签。如果输入文件里同时存在“歌手A-歌曲名一.mp4”和“歌手A - 歌曲名一.mp4”这两种模式上面那个正则已经兼容了因为\s*-\s*的意思就是“连字符两边可以有任意数量的空格”。但如果遇到下划线分隔的文件名“歌手B_歌曲名二.mp4”就需要改成匹配_或-的分隔符$pattern ^(.*?)[_\-\s](.*?)\.mp4$这里用[_\-\s]表示分隔符可以是下划线、连字符、空白字符中的一个或多个。但这里又会出现一个问题如果歌手名或者歌曲名本身带空格比如“Various Artists - New Song.mp4”这种正则就会错误地在空格处断开。所以没有万能正则只有针对你的文件名统计结果设计的最优正则。这也是为什么前面强调要先看一遍文件名而不是直接抄一段代码就开跑。还有一个容易被忽视的点正则中的\.必须转义因为.在正则里代表任意字符。如果你写(.*?).mp4$它也能工作但会把“歌曲名Xmp4”这种缺少点号的文件名也匹配进来这就是一些批量改名脚本会莫名其妙改错文件的原因之一。2.3 命名规则设计为什么我统一命名为“歌曲名 - 歌手.mp4”提取出歌手和歌曲名之后下一步是决定新文件名格式。很多人第一反应是保持原格式“歌手 - 歌曲名.mp4”毕竟看着顺眼。但我在实际使用中发现音乐播放器和手机视频App的排序逻辑往往按文件名的第一个字符走。如果首字符是歌手名同一歌手的歌曲会被聚在一起可一旦文件多了每个歌手的歌曲之间又被其他歌手的名字插开想看某个歌手的所有视频反而要翻页找。反过来如果命名成“歌曲名 - 歌手.mp4”文件名首字符是歌曲名很多播放器按名称排序时就会把所有歌曲按名称字母排序视觉上更接近“专辑曲库”的顺序。当然这个取舍看个人习惯没有标准答案。关键是在脚本开始运行前把规则定下来并且集中在一处定义不要在脚本里到处写死。我最终定的规则是干净版本歌曲名 - 歌手.mp4如果歌手名未知或为空歌曲名.mp4不再保留多余的“未知歌手”字样如果文件名里带“1080p”“HD”“Official”这类后缀标签提取歌手和歌曲名时直接剥离这个规则看起来简单实际操作时却要处理几个边界万一歌曲名里本身包含“ - ”怎么办万一同一个歌手有大量同名歌曲怎么办这属于重名冲突问题后面第4章会专门讲处理方案。命名规则设计时一定要预想“同名文件”和“文件名长度超过Windows限制”这两种极端情况否则批量脚本跑到一半报错或者把文件改成同名后互相覆盖那损失就大了。3. 完整PowerShell脚本从扫描到重命名的全流程实现3.1 脚本整体结构与工具函数把需求理清楚后我写的PowerShell脚本大致分成六个阶段定义目录、扫描文件、正则匹配、提取字段、试运行预览、正式重命名。推荐把“试运行预览”单独拿出来作为一个开关参数这比我以前直接跑简直提升了不止一个安全等级——你永远不知道真实文件名里藏着什么意外。先看脚本框架param( [string]$Directory C:\Users\Public\Music\Beautiful Chinese Music Selected Playlist, [switch]$WhatIf $false ) $ErrorActionPreference Stop $logPath Join-Path $Directory rename_log.csv $files Get-ChildItem -Path $Directory -Filter *.mp4 -File这里的param块允许你在命令行传入目录路径不用每次改脚本里的硬编码路径。WhatIf开关是用来做“试运行”的也就是预览将要发生的改动而不实际执行这个参数后面细讲。特别注意一行$ErrorActionPreference Stop。这行的意思是一旦某个命令发生错误立即停止整个脚本而不是让PowerShell默认“非致命错误继续执行”的行为。批量重命名这类有破坏性操作一旦中途出错最好停下来让你人工确认而不是带着错误状态继续把文件都改了。这一点我在早期脚本里没加结果某次因为两个文件重名Rename-Item报了个非终止错误脚本继续跑完后一半文件改乱了排查半天才恢复。3.2 从文件名提取歌手与歌曲名的核心实现提取这部分是整篇文章最核心的代码。我用了一个foreach循环遍历所有MP4文件然后对每个文件名做正则匹配。匹配成功的提取字段匹配失败的单独记录到另一个日志文件绝对不静默跳过。$results foreach ($file in $files) { $baseName $file.BaseName $pattern ^(.*?)\s*-\s*(.*)$ if ($baseName -match $pattern) { $artist $matches[1].Trim() $title $matches[2].Trim() # 清理常见的多余后缀标签 $title $title -replace \s*\((Official\s*)?(Music\s*)?Video\s*\)\s*$, $title $title -replace \s*(1080p|720p|HD)\s*$, # 生成新文件名统一为歌曲名 - 歌手.mp4 $newName {0} - {1}.mp4 -f $title, $artist [PSCustomObject]{ OldName $file.Name NewName $newName Artist $artist Title $title } } else { Write-Warning 未能匹配的文件: $($file.Name) [PSCustomObject]{ OldName $file.Name NewName Artist Title } } }这段代码里有几个细节值得展开。第一个细节是$matches[1].Trim()和$matches[2].Trim()。正则里我已经处理了连字符前后的空格\s*但Trim()依然是必要的万一某文件名是“歌手A - 歌曲名”多个空格非贪婪匹配到的字段边界可能残留一个空格。这是低成本保险。第二个细节是标题清理的正则。-replace \s*\((Official\s*)?(Music\s*)?Video\s*\)\s*$, 这个表达式把“ (Official Music Video)”“ (Music Video)”这类常见后缀去掉。写这类正则时一定要在末尾加$锚点否则会把歌名中间的“ (Live)”也误删。每次加清理规则都建议先跑一遍测试再放到批处理里。第三个细节是输出一个PSCustomObject对象而不是直接重命名。这意味着脚本先扫描并计算所有新文件名把结果保存下来人肉检查没问题之后再执行重命名。这个“计算和操作分离”的思路是避免批量重命名事故的最好方式。3.3 试运行与正式执行安全重命名的两个阶段我强烈建议任何重命名脚本都内置一个“试运行”模式。PowerShell的-WhatIf参数可以直接传给Rename-Item它会报告“如果执行会怎么样”而不会真的去改文件。放到脚本里就是if ($WhatIf) { Write-Host 试运行模式不会实际重命名 -ForegroundColor Yellow $results | Where-Object { $_.NewName -ne } | Format-Table OldName, NewName -AutoSize } else { $results | Where-Object { $_.NewName -ne } | ForEach-Object { $oldPath Join-Path $Directory $_.OldName $newPath Join-Path $Directory $_.NewName if (Test-Path -LiteralPath $newPath) { Write-Warning 目标文件已存在跳过$($_.NewName) } else { Rename-Item -LiteralPath $oldPath -NewName $_.NewName } } }这里Test-Path判断新路径是否已存在防止两个文件被改成同一个名字时发生覆盖。这是批量重命名里最基础也最重要的防呆检查。目标文件已存在时跳过并报警告比覆盖后追悔莫及要强得多。执行时先跑一次试运行把几十个“旧名字 - 新名字”的对应关系扫一遍确认没有离谱的转换结果后再真实执行。整个流程大概两三分钟就能完成。3.4 生成操作日志给后续排查留个后门重命名完成后把操作记录导出成一个CSV日志文件。不要小看这一步。我经历过一次用其他工具批量改名后想撤销因为没有日志根本不知道哪些文件原来叫什么恢复了很久才搞定。有了日志将来反悔时可以直接按日志反向操作。$results | Export-Csv -Path $logPath -NoTypeInformation -Encoding UTF8 Write-Host 处理完成日志已保存到: $logPath -ForegroundColor Green在$WhatIf模式下不要写这个日志因为实际并没有改动。真实执行后写日志并且日志里记录OldName和NewName两个字段这就是完整的操作审计。如果你将来想更进一步甚至可以记录RenamedAt时间戳字段但我个人觉得没必要除非你在一个团队环境里管理共享素材库。3.5 进阶补充从文件内部元数据读取歌手信息如果某个场景下文件名里根本没有歌手信息或者文件名里的歌手名和MP4文件内部的元数据不一致上述基于文件名的方案就失效了。这种情况要直接从文件内部读取元数据。Windows系统有一个自带COM组件Shell.Application可以读取MP4等媒体文件的元数据属性包括艺术家、标题等。PowerShell调用它非常轻量不需要装第三方库$shell New-Object -ComObject Shell.Application $folder $shell.Namespace($Directory) $fileItem $folder.ParseName(歌手A - 歌曲名一.mp4) $artist $folder.GetDetailsOf($fileItem, 13) # 13 通常对应艺术家属性 $title $folder.GetDetailsOf($fileItem, 21) # 21 通常对应标题属性这里属性索引号根据不同的Windows版本有差异13通常是“艺术家”21通常是“标题”但最好先在本机测试一下索引对应关系。这个方法的好处是无论文件名怎么变都能从MP4内部Tag提取标准字段坏处是如果MP4本身没写入元数据比如从某些网站直接下载的文件那也读不出来。所以我一般把方案顺序定为优先从文件名提提不到时再尝试元数据提两个都拿不到就归为“需要人工处理”的文件。4. 常见问题与排查技巧实录4.1 匹配失败为什么有些文件名就是提取不出来最常见的匹配失败原因有两个一个是文件名模式超出了正则预设另一个是文件名的扩展名判断出了问题。比如文件名“歌手A feat. 歌手B - 歌曲名.mp4”里feat.这个缩写被某些播放器写作“feat”不带点有的写作“ft.”。如果你的正则用了^(.*?)\s*-\s*(.*?)\.mp4$这个文件其实还是能匹配的歌手名会是“歌手A feat. 歌手B”这没问题。真正匹配失败的是这种“歌手A_歌手B_歌曲名.mp4”因为分隔符是下划线而且没有“ - ”结构那就需要单独的正则或手工处理。排查方法很简单脚本里我已经写了Write-Warning 未能匹配的文件: ...把打印出来的文件名收集起来再看一眼统计规律需要的话给这些特殊模式加第二套正则。不要试图写一个万能正则那只会让正则难以维护。4.2 重名冲突与Windows文件名限制重名冲突的处理原则是绝不覆盖先跳过人工处理。我在脚本里用Test-Path做了判断只要目标文件已经存在就跳过。批量处理时如果出现大量重名极其有可能是命名规则设计有缺陷——比如“歌曲名 - 歌手.mp4”如果同一歌手对同一首歌有多个不同版本就会冲突。这时候可以在新文件名里追加序号后缀比如“歌曲名 - 歌手 (1).mp4”但前提是要判断同名数量这会让脚本复杂度增加不少。作为初版方案先跳过重名、人工处理反而更安全。Windows文件名长度上限是255个字符左右完整路径路径字符数限制约260个字符。中文文件名每个字算一个字符看起来不太容易超但如果歌曲名特别长有些现场版歌名动辄几十个字加上目录路径和歌手名可能触发系统限制。遇到这种情况Rename-Item会抛异常脚本里因为设置了$ErrorActionPreference Stop就会暂停运行这时再人工处理该文件名比如截断歌曲名长度。4.3 文件占用与只读属性重命名时如果文件正被播放器或下载工具占用会抛出正在使用异常。建议在跑批处理之前关掉所有可能挂着该文件夹的媒体播放器——我踩过这个坑VLC开着播放列表批量改到一半报错还以为是脚本Bug排查了半天才发现是VLC锁住了文件。只读文件理论上可以重命名但如果是“受保护的系统文件”或隐藏文件Get-ChildItem -Filter *.mp4默认不会包含它们。如果需要处理隐藏文件要加-Force参数。不过对正常音乐素材文件来说这个场景很少出现。4.4 常见问题速查表问题现象可能原因排查与处理某些文件未被匹配文件名格式与预设正则不符打开日志中“未能匹配的文件”列表人工检查必要时补充第二套正则改名后文件变成乱码PowerShell控制台编码与文件系统不一致在PowerShell窗口执行[Console]::OutputEncoding [Text.Encoding]::UTF8或检查脚本文件本身是否以UTF-8编码保存目标文件名已存在两个源文件提取后生成相同的新名称脚本已跳过并报警告人工决定删除旧重复文件或追加序号脚本报“路径太长”新文件名目录路径超过Windows限制人工截断超长歌曲名或把文件移动到更浅的目录层级运行后文件没变化WhatIf模式没有关闭检查命令行是否误加了-WhatIf参数脚本默认模式是正式执行文件正在使用无法重命名播放器或编辑器占用文件关闭相关程序重新运行脚本日志CSV打开乱码编码不是UTF-8 with BOMPowerShell导出CSV时建议加-Encoding UTF8Excel打开还乱码就改用记事本中转或用文本编辑器打开4.5 几个实测下来很值钱的习惯最后一个经验。批处理重命名这种事我做了很多次现在总结出三条习惯每次执行都让我少踩不少坑第一条任何批量操作之前先复制三个文件到测试目录跑一遍脚本。不要直接在大目录上跑。我第一次写这个脚本时直接对着两百多个文件执行结果发现还要微调清理正则来回折腾了很久。后来学乖了先复制三五个典型文件到临时目录跑通了再去处理真实目录。第二条脚本里永远不要写删除文件的逻辑。哪怕你确定某个文件重复了也不要在脚本里顺手删掉。重命名的可逆性比删除高得多出问题还能按日志恢复删除基本就没了。如果确实需要清理等重命名确认无误后再人工去处理。第三条运行完脚本后随便打开几个文件确认一下播放器显示是否正常而不是只看文件名列表。我遇到过一种情况文件名看着对但文件关联的播放器数据库缓存还是旧的名字导致播放列表显示错乱。确认“显示层”正常才算是真正完成了这次整理工作。经验收尾这个脚本思路还能用在哪写到这里方法论其实已经讲透了。最后分享一点个人感受批量重命名MP4文件这件事只是一个很小的技术切片但它背后的“扫描输入格式 → 设计提取规则 → 先试跑后执行 → 记录操作日志”这个套路几乎可以平移到我日常的很多素材整理工作中。比如处理图片时去掉相机拍摄前缀、整理电子书文件名里的多余标点、批量规整字幕文件与视频文件的对齐命名都是同一个逻辑框架。区别只在于正则和扩展名变了PowerShell脚本的骨架几乎不用动。我在实际工作中最常用到的一个小技巧是把脚本里的目录参数化之后在文件管理器地址栏直接输入powershell -File Clean-MusicFileNames.ps1 -Directory 某个路径配合-WhatIf参数先预览不影响任何文件。这样长期用下来整理素材库的效率比手动拖拽、右键重命名高出一个数量级。如果后续还想升级这个脚本我觉得有两个方向值得尝试一是把“未能匹配的文件”自动生成一个HTML报告里面包含文件名和推荐命名建议这样处理特殊文件名时可以边看边改二是加上重复文件检测在重命名前先提示“同一歌手同一歌曲可能有多个版本”让你决定是否保留全部版本。这两个方向都需要额外的逻辑和测试但对于长期维护大素材库的人来说投入产出比是划算的。你可以先跑通今天这个版本再按自己的实际需求往这两个方向扩展。

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

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

免费获取报价 →
↑