场景:将数百张产品图片按SKU编码重命名并归类到子文件夹
做电商运营、仓储管理或者产品摄影的朋友,大概率都遇到过这种“绝望”时刻:
相机导出的几百张产品图,文件名全是 IMG_001.jpg、DSC_002.png这种毫无意义的格式。而手头有一张Excel表,A列是旧文件名,B列是对应的SKU编码(比如 SKU-2024-001)。老板要求你:半小时内,把所有图片按SKU重命名,并且按品类(比如“男装”、“女装”、“配件”)放进不同的文件夹里。
手动改?点几百次鼠标,不仅慢,还容易漏。今天我们就用Python和VBA两种方案,彻底解决这个痛点。
一、需求拆解与准备工作
在开始写代码前,我们先把逻辑理清楚。这是避免写出“屎山代码”的关键一步。
1. 数据准备
假设你的文件夹结构是这样的:
D:\ProductPhotos\│ IMG_001.jpg│ IMG_002.jpg│ IMG_003.jpg│ mapping.xlsx
mapping.xlsx的内容如下:
旧文件名 (OldName) | SKU编码 (SKU) | 品类 (Category) |
|---|
IMG_001.jpg | SKU-2024-001 | 男装 |
IMG_002.jpg | SKU-2024-002 | 女装 |
IMG_003.jpg | SKU-2024-003 | 配件 |
2. 逻辑流程
无论是Python还是VBA,核心逻辑都是一致的:
读取映射表:从Excel中读取“旧文件名-SKU-品类”的对应关系。
遍历文件:扫描目标文件夹中的所有图片文件。
匹配与重命名:找到旧文件名对应的行,将其重命名为 SKU-2024-001.jpg。
创建目录:根据“品类”字段,创建对应的子文件夹(如“男装”)。
移动文件:将重命名后的文件移动到对应的子文件夹中。
二、Python方案:现代化与优雅的 pathlib
Python在处理文件批量操作时,有两个流派:一个是传统的 os+ shutil,另一个是更现代的 pathlib。强烈推荐使用 pathlib,因为它把路径当成对象来处理,代码可读性极高,且跨平台兼容性更好(不用操心Windows的反斜杠 \` 和Mac/Linux的正斜杠/` 问题)。
1. 核心库导入
import pandas as pdfrom pathlib import Pathimport shutil
2. 完整代码实现
下面的代码不仅实现了功能,还加入了异常处理和日志打印,这是专业脚本的标配。
def organize_product_photos(excel_path, photo_dir): """ 批量重命名并归类产品图片 :param excel_path: 映射表Excel路径 :param photo_dir: 图片文件夹路径 """ # 1. 读取Excel映射表 try: df = pd.read_excel(excel_path) # 清洗列名,去除可能存在的空格 df.columns = df.columns.str.strip() except Exception as e: print(f"读取Excel失败:{e}") return # 2. 定位图片文件夹 photo_path = Path(photo_dir) # 3. 遍历DataFrame中的每一行映射关系 for index, row in df.iterrows(): old_name = row['旧文件名'] sku = row['SKU编码'] category = row['品类'] # 构建旧文件的完整路径 old_file = photo_path / old_name # 检查旧文件是否存在 if not old_file.exists(): print(f"警告:文件 {old_name} 不存在,跳过。") continue # 4. 构建新文件名(保留原扩展名) # 获取文件后缀,例如 .jpg suffix = old_file.suffix new_name = f"{sku}{suffix}" # 5. 创建分类子文件夹 # mkdir(parents=True): 如果父目录不存在则创建 # exist_ok=True: 如果目录已存在则不报错 category_dir = photo_path / category category_dir.mkdir(exist_ok=True) # 6. 构建目标文件路径 target_file = category_dir / new_name # 7. 移动并重命名 try: # shutil.move 既可以移动也可以重命名 shutil.move(str(old_file), str(target_file)) print(f"成功:{old_name} -> {category}/{new_name}") except Exception as e: print(f"处理 {old_name} 失败:{e}") print("所有文件处理完毕!")# 执行函数if __name__ == "__main__": excel_file = r"D:\ProductPhotos\mapping.xlsx" photos_folder = r"D:\ProductPhotos" organize_product_photos(excel_file, photos_folder)
3. Python代码深度解析
pathlib的优势:photo_path / old_name这种写法非常直观,避免了 os.path.join()那种繁琐的字符串拼接。
shutil.move:这个函数很强大,如果源路径和目标路径在同一个磁盘,它相当于重命名;如果在不同磁盘,它会先复制再删除源文件。
异常处理:try...except结构保证了即使某个文件处理失败,程序也不会崩溃,而是继续处理下一个文件。
__name__ == "__main__":这是Python的最佳实践,确保代码在被导入为模块时不会自动执行。
4. 进阶优化(干货)
如果你不想依赖 pandas(比如服务器环境没有安装),可以用 csv模块替代Excel读取:
import csvdef read_mapping_csv(csv_path): mapping = [] with open(csv_path, 'r', encoding='utf-8-sig') as f: # utf-8-sig解决Windows下BOM问题 reader = csv.DictReader(f) for row in reader: mapping.append(row) return mapping
三、VBA方案:Excel原生环境的利器
对于大多数办公室白领来说,VBA是离数据最近的开发工具。不需要安装Python环境,直接在Excel里就能跑。
1. 启用FileSystemObject (FSO)
VBA默认没有开启文件系统对象,需要手动引用:
打开VBA编辑器 (Alt + F11)。
点击菜单栏 工具-> 引用。
勾选 Microsoft Scripting Runtime。
2. 完整代码实现
这段代码可以直接放在Excel的VBA模块中运行。
Sub OrganizeProductPhotos() Dim FSO As Scripting.FileSystemObject Dim ws As Worksheet Dim photoDir As String Dim lastRow As Long Dim i As Long Dim oldName As String, sku As String, category As String Dim oldFile As Object, categoryFolder As Object Dim fileExt As String ' 1. 设置工作表和路径 Set ws = ThisWorkbook.Sheets("Sheet1") ' 修改为你的Sheet名 photoDir = "D:\ProductPhotos\" ' 修改为你的图片路径 ' 2. 创建FileSystemObject Set FSO = New Scripting.FileSystemObject ' 3. 获取最后一行 lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row ' 4. 循环处理每一行 For i = 2 To lastRow ' 假设第一行是表头 oldName = ws.Cells(i, 1).Value ' A列:旧文件名 sku = ws.Cells(i, 2).Value ' B列:SKU编码 category = ws.Cells(i, 3).Value ' C列:品类 ' 检查旧文件是否存在 If FSO.FileExists(photoDir & oldName) Then ' 5. 获取文件扩展名 fileExt = FSO.GetExtensionName(photoDir & oldName) ' 6. 创建分类文件夹 If Not FSO.FolderExists(photoDir & category) Then FSO.CreateFolder (photoDir & category) End If ' 7. 移动并重命名 ' Name 语句可以跨文件夹移动并重命名 On Error Resume Next ' 防止重名文件报错中断 Name photoDir & oldName As photoDir & category & "\" & sku & "." & fileExt If Err.Number <> 0 Then Debug.Print "重命名失败: " & oldName & " -> " & sku & "." & fileExt Err.Clear Else Debug.Print "成功: " & oldName & " -> " & category & "\" & sku & "." & fileExt End If On Error GoTo 0 Else Debug.Print "文件不存在: " & oldName End If Next i MsgBox "处理完毕!"End Sub
3. VBA代码深度解析
FileSystemObject (FSO):这是VBA操作文件的瑞士军刀。FileExists检查文件,FolderExists检查文件夹,CreateFolder创建文件夹,GetExtensionName获取后缀。
Name语句:这是VBA特有的语法,用于重命名文件或移动文件。语法是 Name 原路径 As 新路径。它比FSO的 MoveFile方法更直接,但缺点是如果目标文件已存在,会报错,所以配合了 On Error Resume Next使用。
On Error Resume Next:VBA中的错误处理语句,遇到错误时跳过当前行继续执行,防止程序因单个文件错误而崩溃。
四、Python vs VBA:技术选型对照
这是本文的核心对照要点,帮助你在实际工作中做选择。
维度 | Python (pathlib+ shutil) | VBA (FSO+ Name) |
|---|
代码风格 | 面向对象,路径是对象,链式调用优雅 (path.parent.mkdir()) | 过程式,字符串拼接路径,代码相对冗长 |
可读性 | 极高,接近自然语言,维护成本低 | 中等,需要熟悉VBA语法和FSO对象模型 |
环境依赖 | 需要安装Python及 pandas库(或用 csv模块) | 零依赖,Windows系统自带,Excel原生支持 |
错误处理 | try...except结构清晰,捕获异常类型明确
| On Error语句较为粗暴,调试相对困难
|
跨平台 | 完美支持 (Windows, macOS, Linux) | 仅限Windows |
性能 | 处理海量文件(上万级)时性能优势明显 | 处理几千个文件尚可,上万级可能卡顿 |
适用场景 | 复杂的数据清洗、自动化运维、跨平台脚本 | 快速处理Excel相关的小工具、办公自动化 |
总结建议:
五、避坑指南(实战干货)
文件名编码问题:Windows系统经常遇到中文乱码。Python中读取文件时,如果遇到乱码,尝试指定编码 encoding='gbk'或 encoding='utf-8-sig'。
文件占用问题:如果图片正在被Windows照片查看器打开,代码执行时会报错(文件被占用)。确保处理前关闭所有相关文件。
重名覆盖风险:上述代码均未处理“目标文件已存在”的情况。在生产环境中,建议加入判断:如果目标文件存在,要么跳过,要么在文件名后加 _1、_2后缀。
路径末尾反斜杠:VBA中拼接路径时,很容易漏掉文件夹后的反斜杠 \`,导致路径变成D:\ProductPhotosIMG_001.jpg。使用FSO的BuildPath方法可以避免这个问题:FSO.BuildPath(photoDir, oldName)`。
六、课后练习
为了检验你对本文知识点的掌握程度,请完成以下选择题:
在Python的 pathlib模块中,用于连接路径和文件名的最佳方式是?
A. os.path.join(path, name)
B. path + "\\" + name
C. path / name
D. path.append(name)
VBA中,FileSystemObject(FSO) 获取文件扩展名(如 "jpg")的方法是?
A. FSO.GetFileName
B. FSO.GetExtensionName
C. FSO.GetFileType
D. FSO.Extension
在Python中,使用 shutil.move(src, dst)时,如果 dst是一个已经存在的文件夹路径,会发生什么?
A. 报错:文件已存在
B. 将 src移动到 dst文件夹内
C. 覆盖 dst文件夹
D. 什么都不会发生
VBA中的 Name语句主要功能是?
A. 仅能重命名文件,不能移动文件
B. 仅能移动文件,不能重命名
C. 可以同时重命名和移动文件
D. 用于定义变量名称
在处理批量文件重命名时,为了防止程序因单个文件处理失败而整体崩溃,Python和VBA分别通常采用什么机制?
A. Python用 On Error Resume Next,VBA用 try...except
B. Python用 try...except,VBA用 On Error Resume Next
C. 两者都用 if...else判断
D. 两者都没有内置的错误处理机制
答案
C。pathlib重载了 /运算符,使得路径拼接更加直观和安全。
B。GetExtensionName方法专门用于返回文件扩展名。
B。如果目标是一个目录,shutil.move会将源文件移动到该目录下。
C。VBA的 Name语句语法为 Name 原路径 As 新路径,新路径可以包含新的文件夹位置和新文件名。
B。这是两者在错误处理语法上的核心区别。
如果这篇文章帮你解决了工作中的实际问题,欢迎点赞、在看、转发三连!有任何关于办公自动化的难题,也可以在评论区留言,我们下期再见。