不可靠,因Windows的ctime是创建时间,macOS/Linux的ctime是元数据变更时间,且Linux不支持创建时间;应优先用EXIF DateTimeOriginal,fallback到os.path.getmtime()。

直接用 os.path.getctime() 不可靠——Windows 和 macOS 行为不一致,Linux 根本不支持创建时间,实际应优先用修改时间 os.path.getmtime(),再 fallback 到 EXIF 里的拍摄时间(尤其对手机照片)。
为什么不能只靠 os.path.getctime()
Windows 上 os.path.getctime() 返回的是“文件创建时间”,但 macOS 和 Linux 的 ctime 实际是“元数据最后变更时间”(比如 chmod、chown 都会改它),和拍摄时间毫无关系。更麻烦的是:很多同步工具(如 Dropbox、iCloud)或复制操作会重置 ctime,导致归档错乱。
- 手机导出的照片,
ctime往往是导入当天,不是拍摄日 - 从相机卡直接复制的文件,在 Linux 上
ctime可能等于mtime,但仍是写入时间,非拍摄时间 - 真正可靠的来源只有 EXIF 中的
DateTimeOriginal字段
怎么安全提取照片的拍摄日期?
用 PIL.Image 或 exifread 读取 EXIF,但要注意:不是所有图片都有 DateTimeOriginal;JPEG 通常有,PNG/HEIC/WEBP 大概率没有;部分安卓截图或微信转发图会删掉 EXIF。
- 先尝试用
PIL.Image.open()+_getexif()读取36867(DateTimeOriginal)字段 - 失败时 fallback 到
os.path.getmtime(),并用time.localtime()转成datetime.date - 避免用
exifread—— 它不维护了,且对 HEIC 支持差;PIL(即Pillow)更轻量、兼容性好
from PIL import Image
from PIL.ExifTags import TAGS
import time
from datetime import datetime
def get_photo_date(filepath):
try:
img = Image.open(filepath)
exif = img._getexif()
if exif and 36867 in exif:
dt_str = exif[36867]
return datetime.strptime(dt_str, "%Y:%m:%d %H:%M:%S").date()
except:
pass
return datetime.fromtimestamp(os.path.getmtime(filepath)).date()
归档目录结构怎么设计才不踩坑?
别用 "2023-01-01" 这种纯日期名——同一张照片可能跨天(比如凌晨拍的,但文件系统记录为前一天);也别用 "2023/01/01" 多级目录——大量小文件会导致 inode 碎片,macOS Finder 和 Windows 资源管理器在深层嵌套下响应变慢。
立即学习“Python免费学习笔记(深入)”;
- 推荐格式:
"2023-01"(年月),兼顾可读性和目录数量控制 - 目标路径拼接用
os.path.join(root_dir, f"{year}-{month:02d}"),避免手动拼 `/` 或 `\` - 提前检查目标目录是否存在,不存在则
os.makedirs(..., exist_ok=True),否则FileNotFoundError - 移动前加
shutil.move(src, dst),不要用os.rename—— 跨磁盘会失败
批量处理时如何避免误操作和崩溃?
脚本跑一小时后崩在第 3217 张图上,前面的操作没法回滚——必须做原子化保护和日志记录。
- 每张图处理完立刻写一行日志到
archive.log,包含原路径、目标路径、日期、是否成功 - 跳过非图片文件(用
imghdr.what(filepath)或简单后缀判断.jpg/.jpeg/.png/.heic/.tiff) - 遇到权限错误(
PermissionError)或 EXIF 解析异常(AttributeError、KeyError)要捕获,继续下一张,别中断 - 加个
--dry-run参数:只打印将要移动的动作,不真实执行
EXIF 时间和文件系统时间冲突时,以 EXIF 为准;但若两者相差超过 365 天,建议人工抽检——可能是相机时间没校准,或者图被反复编辑过。


















