直接用os.rename()重命名照片易出错,因Exif的DateTimeOriginal常为空或被覆盖;须优先读取Exif时间,fallback至修改时间,检查目标路径是否存在,并过滤非法字符、控制文件名长度,批量前应dry-run验证。

为什么直接用 os.rename() 重命名会出错
很多人一上来就写循环 + os.rename(),结果发现照片全乱了:有的文件名重复,有的时间戳是 1970-01-01,甚至报 FileNotFoundError。根本原因是相机导出的 JPG 文件不一定都带完整 Exif,有些被手机/微信二次保存过,DateTimeOriginal 字段直接为空;还有些用 Windows 复制后,系统把原始时间戳覆盖成了复制时间。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须先用
PIL.Image或exifread(更轻量)读取原始 Exif,优先取EXIF DateTimeOriginal, fallback 到Image DateTime,再 fallback 到文件修改时间(os.path.getmtime()) - 别依赖
os.stat().st_ctime—— 它在 macOS/Linux 是“元数据变更时间”,不是创建时间,不可靠 - 重命名前加
os.path.exists()检查目标路径,避免覆盖;冲突时用-1、-2后缀递增
怎样用 exifread 安全提取拍摄日期
exifread 比 PIL 更专注、更快,且不加载图像像素,适合批量处理。它返回的字段值是字符串,格式固定为 "YYYY:MM:DD HH:MM:SS",但注意中间是英文冒号,不是短横线,直接 .replace(':', '-') 就能转成常见日期格式。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 安装:
pip install exifread - 打开文件要用
'rb'模式,否则exifread.process_file()会静默失败 - 检查字段是否存在:
if 'EXIF DateTimeOriginal' in tags:,不要直接索引,否则抛KeyError - 解析后建议用
datetime.strptime(..., '%Y:%m:%d %H:%M:%S')转成对象,方便做排序或去重
重命名时如何避免 Windows 文件名非法字符和长度限制
Windows 对文件名有硬性限制:不能含 < > : " / \ | ? *,总长不能超 260 字符。相机拍的照片 Exif 里可能有空格、冒号、中文,直接拼进文件名会触发 OSError: [WinError 123]。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 日期部分用
strftime('%Y-%m-%d_%H-%M-%S'),确保只含数字、短横线、下划线 - 原文件名中的非 ASCII 字符(如中文、emoji)用
unicodedata.normalize('NFD', s).encode('ascii', 'ignore').decode()过滤,或直接丢弃 - 最终文件名控制在 50 字符以内(含扩展名),例如:
2024-05-22_14-32-08.jpg,留足空间给序号和后缀 - 扩展名统一小写:
os.path.splitext(path)[1].lower(),避免出现.JPG和.jpg被当成两个不同文件
批量处理时怎样防止误操作导致原始文件丢失
重命名本身不删原文件,但一旦路径写错、循环逻辑有 bug,可能把几百张照片全改名成同一个名字,最后只剩一张。这不是理论风险,是真实高频事故。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 首次运行前,加开关参数(如
--dry-run),只打印「将从 A 改为 B」,不执行os.rename() - 所有
os.rename()前加try/except OSError as e:,捕获并记录错误,继续处理下一张 - 原始照片目录不要设为当前工作目录(
.),用绝对路径,避免相对路径在脚本位置变化时指向错目录 - 真正执行前,用
shutil.copy2(src, dst)先复制一份带新名的副本,确认无误后再删原文件(仅限你明确需要「移动语义」时)
最麻烦的不是代码写不对,而是某张照片的 Exif 时间比另一张早却排在后面——因为 FAT32 文件系统不保证目录遍历顺序。如果对时序敏感,一定要先按提取出的时间戳排序,再重命名。


















