资讯动态

用Python按文件名关键字批量分组文件,歌曲按歌手自动归档

发布时间:2026/9/9 20:55:55 来源:尧图企业网站定制
你是不是也遇到过这样的情况某个文件夹里堆了两三千首歌歌手五花八门文件名叫“周杰伦 - 七里香.mp3”“林俊杰 - 江南.flac”你想按歌手分好文件夹方便车里直接挑结果一想到要一首一首去拖就头大。标题里那句“按文件名关键字分为n份、用关键字给文件分组、歌曲根据歌手分组”其实就是同一件事的三种说法读文件名里能看出来的线索把一堆杂乱文件按“名字里含什么”塞进对应文件夹。这篇文章我会把几种常见需求拆开讲清楚给你能直接复制的Python脚本再补上不写代码的替代方案适合文件乱到想摔键盘但又不想靠手工一个个拖的人。1. 需求拆解三种表面不同的需求底层是同一件事1.1 三种高频场景你想解决的到底是哪一种先说第一类也是标题里最直白的场景歌曲按歌手分组。你下载过一个音乐包里面可能有华语、粤语、英文歌混在一起文件名通常是“歌手 - 歌名.mp3”或者“歌手_歌名.flac”。你要的不是改文件名而是把同一个歌手的歌都挪进同一个文件夹。第二类是资料按关键字归档。比如你是做工程或客服的一个目录下有几十份“2023-北京-采购合同.pdf”“2023-上海-服务合同.pdf”你想按“北京”“上海”这种地区字段或者按合同类型字段归类。这里的关键字不再是歌手名而是你指定的一组关键词。第三类是“平均分成n份”。有些场景下你不需要知道内容只需要把一个有500个文件的目录均匀拆成5份比如给外包整理数据集、把文件分给不同的人处理。这个逻辑和“按歌手分组”略有不同它不关心文件名是什么只关心顺序编号。不管你属于哪一类背后的程序逻辑只有四步遍历目录里的每个文件从文件名里提取关键信息决定它应该去哪个文件夹移动或复制过去。如果你熟悉SQL里的GROUP BY可以把它理解为“把文件路径当成一条记录文件名里的关键字当成分组字段然后按字段值归组”只不过我们要亲手把这个逻辑写成脚本而已。1.2 为什么用脚本而不是手工拖拽或现成工具几百个文件手工拖拽一下午就没了而且极易漏拖错拖。几千个文件更是灾难。市面上确实有一些文件整理工具但我试过不少它们通常在“按类型扩展名分类”上做得不错遇到“按文件名里的自定义关键字分组”这种需求就捉襟见肘了。脚本方案的好处有三点第一规则完全透明你不会把文件交给一个黑盒工具最后发现规则理解错了文件被乱移第二可复用今天的场景是按歌手分歌下周变成按客户分合同改一行规则就行第三出错可复盘脚本会打印每一步操作真出了问题能追回来。说句实话Python并不难哪怕你完全没接触过把本文的代码复制下来改几个路径就能直接跑。2. 核心逻辑从文件名里取关键字的三种模式2.1 模式一白名单包含匹配适合“分类名已经确定”举个例子你明确知道这批歌里只有周杰伦、林俊杰、陈奕迅、薛之谦这几位歌手那就可以维护一个“白名单”列表然后用in判断文件名里是否包含某个歌手名。代码思路是这样的keywords [周杰伦, 林俊杰, 陈奕迅, 薛之谦] for filename in os.listdir(source_dir): for kw in keywords: if kw in filename: # 移动到 kw 文件夹 break这里有个容易翻车的地方中文文件名在Linux和Windows下的处理习惯不同。Linux严格区分大小写Windows不区分所以如果你在Windows下匹配“jay”文件名里的“Jay”也能命中但换到Linux后同样的代码就匹配不上了。还有一类问题更隐蔽关键词“林俊杰”如果出现在“林俊杰经典歌曲合集.txt”这种文件名里它也会被命中。按白名单匹配的优点是代码简单缺点是误命中率高适合“分类名称少且不容易混淆”的场景。2.2 模式二分隔符提取适合“文件名格式很规范”大部分音乐文件命名都有一个规律比如“歌手 - 歌名.mp3”中间用空格加横线加空格隔开。你可以不维护任何歌手名单直接用分隔符把歌手名从文件名里切出来。parts filename.split( - ) if len(parts) 2: singer parts[0].strip()这个方案比白名单匹配快得多而且不会出现“名单漏人”的情况。它的前提是文件名必须足够规范如果某些文件是“歌名.mp3”没有歌手段或者分隔符是下划线而不是横线就需要先做一步标准化。我的习惯是先用正则把几种常见分隔符统一成同一个符号再拆分这样能兼容大多数脏数据。文件名就是文件的“身份证”字段越规整提取越简单越不需要靠猜。2.3 模式三“n份”要分先搞清楚是按内容还是按数量标题里有“分为n份”这个词其实有歧义。一种理解是“先按歌手分组如果某个歌手的歌太多再拆成多个文件夹”比如周杰伦有200首你希望每50首一个子文件夹另一种理解更简单粗暴不管内容500个文件平均分到5个文件夹。如果是按数量拆核心逻辑是取模或者整除n 5 # 想分成5份 for i, file in enumerate(all_files): target_dir os.path.join(source_dir, fpart_{i % n 1}) shutil.move(file, target_dir)如果按“分组后再拆”比如按歌手分组后每组最多40首那就用一个计数器每移动40个文件就新建一个子目录。这两种“n份”含义差别很大写脚本前一定要先确认需求否则很容易白跑一遍。2.4 中文文件名的乱码问题越早重视越省事中文文件名在Windows上默认用GBKLinux和macOS默认用UTF-8。用Python的pathlib和字符串函数处理中文文件名一般情况下没问题但有两个场景容易踩坑一是从FTP、网盘或老设备拷过来的文件文件名编码已经被搞乱了显示成“锟斤拷”之类的乱码二是控制台打印中文路径时在Windows的cmd里经常出现乱码这不是逻辑错只是输出编码问题。我的建议是处理文件路径时尽量统一用UTF-8脚本文件本身保存成UTF-8编码。如果文件名已经乱掉先用批量改名工具修一遍再跑分组效果会好很多。批量处理前最安全的做法是先在脚本里把移动操作注释掉改成只打印文件路径干跑一遍确认结果再真正执行移动。3. 实操两组直接能跑的 Python 脚本3.1 基础版按歌手名单批量建文件夹并移动假设你的音乐在D:\Music目录下散落着大量命名不规范的文件。第一步把下面代码里的source_dir改成你的目录把keywords换成你的歌手名单然后先跑带注释的“预览模式”确认无误后再开启移动。import os import shutil source_dir rD:\Music keywords [周杰伦, 林俊杰, 陈奕迅, 薛之谦] # 预览模式先注释掉 shutil.move 那两行改成 print for name in os.listdir(source_dir): full_path os.path.join(source_dir, name) if os.path.isdir(full_path): continue matched False for kw in keywords: if kw in name: target_dir os.path.join(source_dir, kw) os.makedirs(target_dir, exist_okTrue) # 预览时取消下一行注释把真正的 move 注释掉 print(f[移动] {name} - {kw}) # shutil.move(full_path, os.path.join(target_dir, name)) matched True break if not matched: print(f[未分类] {name}) # shutil.move(full_path, os.path.join(source_dir, _未分类, name))运行预览后你会看到类似这样的输出[移动] 周杰伦 - 七里香.mp3 - 周杰伦 [移动] 林俊杰 - 江南.flac - 林俊杰 [未分类] 一些随机的音频文件.mp3确认无误后把注释切换回来再跑一遍。这里我特意加了一个_未分类的兜底目录它的价值在于没有匹配到任何歌手的文件不会被留在原地而是统一进到“未分类”方便你回头检查而不是跑完脚本后源目录里还剩一堆不知道去哪了的文件。3.2 进阶版用正则自动提取任意歌手名如果歌手名单太长或者你根本不想维护名单推荐用正则提取。以“歌手 - 歌名.mp3”这种命名格式为例import os import re import shutil from pathlib import Path source_dir Path(rD:\Music) # 匹配任意非空内容 空格横线空格 任意内容 常见音频后缀 pattern re.compile( r^(?Psinger.?)\s*[-_]\s*(?Ptitle.)\.(?Pextmp3|flac|wav|m4a|ogg|ape)$, re.IGNORECASE ) for file in source_dir.iterdir(): if not file.is_file(): continue m pattern.match(file.name) if not m: continue singer m.group(singer).strip() target_dir source_dir / singer target_dir.mkdir(exist_okTrue) dest target_dir / file.name # 同名文件自动加序号防止覆盖 if dest.exists(): dest target_dir / f{file.stem}_1{file.suffix} shutil.move(str(file), str(dest)) print(f{file.name} - {singer})这个脚本里有个容易被忽略但又很重要的细节file.is_file()。它会自动跳过目录包括脚本执行过程中已经创建出来的歌手文件夹。如果不加这个判断极端情况下脚本会把“周杰伦”这个文件夹也当成一个文件去匹配非常容易出逻辑混乱。另外正则表达式限制只匹配.mp3、.flac等常见音频后缀这样能避免把其他类型文件也带进来。如果你要处理的是图片或文档把扩展名那一段换成你自己的文件类型即可。实际跑的时候如果遇到命名不统一的文件比如歌手和歌名之间没有空格就会自动进入“无法匹配”的状态不会报错但你要注意查看哪些文件没被处理。3.3 双击就能跑给脚本做一层壳写完脚本后你肯定不想每次整理文件都打开终端敲命令。Windows下可以直接把文件后缀改成.pyw双击运行但不方便看日志。更好用的小技巧是写一个.bat批处理双击后自动调用Python并停住让你能看清运行结果echo off chcp 65001 nul python D:\scripts\group_music.py pause第一行chcp 65001 nul是把控制台代码页切换成UTF-8避免中文文件名打印出来是乱码。如果你没装Python安装时记得勾选“Add Python to PATH”。有了一次双击能跑的入口你以后整理文件就再也不用打开编辑器了。4. 常见问题与排错指南4.1 问题速查表以下是我自己这些年反复遇到的问题按“现象、原因、解决”列的速查表建议先收藏再慢慢看。现象原因解决办法中文文件名在控制台打印乱码控制台代码页和脚本编码不一致bat里加chcp 65001Python脚本保存为UTF-8移动后脚本又把目标文件夹扫进去目标文件夹在源目录内遍历时没有过滤目录统一用file.is_file()或os.path.isfile过滤移动时报“文件被占用”歌曲被播放器、编辑器等程序打开关掉相关程序把移动改成复制目标文件夹出现同名文件被覆盖不同歌手有同名歌曲同名概率不低检测到dest.exists()时追加_1、_2有些分组的文件数量特别少关键字匹配太严格比如全角/半角空格差异先做标准化用正则替换统一分隔符提示文件名或目录名太长Windows默认路径长度限制260字符缩短路径或修改注册表开启长路径支持跨盘符移动特别慢或失败shutil.move跨盘时会变成复制删除尽量把源目录和目标目录放在同一盘符内第6条“路径太长”在Windows里比较常见尤其是文件层级深加上中文文件名时。Windows 10/11专业版可以通过注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled把值改成1并重启来解除限制但修改注册表前一定要备份。如果只是在临时整理文件我更推荐直接缩短顶层目录路径比折腾系统设置安全得多。4.2 我踩过的几个坑第一次写分组脚本时踩过最大的一个坑我在循环里每移动一个文件就重新列一次目录导致刚刚创建的目标文件夹也被当成了源文件最后文件被一层层套娃移动到了“歌手/歌手/歌手”目录下。后来我强制自己把所有源文件先一次性收集成列表再统一做移动绝不动态扫描目录这个问题再也没出现过。第二个坑是跨盘符操作。有一次我把源目录放在D盘目标目录放在C盘文件大一点的音频shutil.move实际上会发生“先复制再删除”的行为中间如果磁盘空间不足或断电源文件可能有残损风险。我的经验是整理文件尽量同盘操作必须跨盘时先做小批量测试不要一次性放大几千个文件进去。第三个坑是“未分类”文件夹没人管。一开始我以为加了兜底目录就万事大吉结果过了半年打开一看未分类里堆了两百多个文件全是当时跑脚本时没匹配上的。所以后来我把兜底目录也做了规则化每周定期打开未分类看一眼或者把脚本的匹配逻辑调整得更宽松让未分类数量少到可以手工处理。第四个坑也是最容易犯的忘了加“同名文件自动加序号”。文件名里“歌手 - 歌名”结构看着没问题但同一个歌名被不同歌手演唱或者同一个文件被重复下载过很常见。目标已存在同名文件时直接shutil.move会覆盖必须加一个判断重名时追加后缀。这个逻辑建议从一开始就写进脚本哪怕你暂时用不到。5. 扩展从歌曲分组到任意文件整理5.1 找出你文件名的规律其他场景就能套用按歌手分组只是这类需求里最简单的一种。你只要会做一套“观察文件名 → 提取关键字段 → 移动文件”的动作就能套用到无数场景。比如照片整理。你的相册导出了成百上千张照片文件名可能是2023-01-01_北京_景点.jpg那就把“北京”当关键字分组或者把“2023-01”这个月份当关键字分组。和歌曲不同的是照片的名称通常没有统一的分隔符写规则前需要先多打印几个文件名观察一下确定哪些字段是稳定存在的。比如合同文件。文件名是2023-北京-XX公司-采购合同.pdf中间的“北京”就是地理维度的关键字“采购合同”是合同类型维度的关键字。你可以选择先按地区分再在地区目录里按合同类型分这就变成了两级分组逻辑上就是把脚本跑两遍。再比如日志文件服务端每天会生成app_20230101.log想按月份归档可以提取第5到第6位字符作为月份生成202301目录。总之核心思想都是“从文件名里找一个稳定字段按它的值去建目录”。我的建议是先做一次自检列出一批文件名看看哪个字段能稳定代表分类分隔符是什么有没有明显异常。这个自检最多花你十分钟却能在后面省下大量返工时间。5.2 不想写代码PowerShell一行流也能干如果你用的是Windows实在不想装Python那PowerShell也能完成大部分需求。比如还是按歌曲分组在音乐目录里打开PowerShell直接执行Get-ChildItem -File | ForEach-Object { $singer ($_.Name -split - )[0] if ($singer) { New-Item -ItemType Directory -Force -Path $singer | Out-Null Move-Item $_.FullName -Destination $singer } }这段脚本的意思很直白列出所有文件取文件名里第一个“ - ”前面的部分作为歌手名建目录后移动过去。PowerShell的-split是分割字符串[0]就是取第一段。这种方案的优点是零依赖缺点是规则复杂时写起来很痛苦正则处理也比Python繁琐。如果你连命令行都不想碰我的建议是先用批量改名工具比如Advanced Renamer、PowerToys里的PowerRename、以及各类图片批量重命名工具把文件名统一成规范格式比如从周杰伦 - 七里香.mp3规范成周杰伦 - 七里香.mp3或把不规律的文件名先修好再回头用本文的脚本按分隔符分组。先规范命名、再按分隔符分组这个组合是我实测下来最高效的路径远比在脚本里写一堆容错正则省心。最后再分享一个小经验批量整理文件前永远先做一次“print预览”把要移动的文件和去向打印出来人工扫一眼再执行。这不是拖沓而是用几十秒的检查换掉几十个文件的灾难后恢复时间。脚本不怕慢怕的是你把规则理解错了图快直接跑结果文件被移得七零八落。整理文件是一次性的、低成本的事情但做好分类规则能让你以后每次找文件都舒服这笔账怎么算都值得。

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

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

免费获取报价