go标准库不支持jpeg exif读取,需用第三方包;常见错误包括未校验文件有效性、误处理无exif的图片(如手机直出、微信图),应先检查jpeg头、文件大小,再按datetimeoriginal等优先级解析时间,并安全重命名与并发控制。

Go 读取 JPEG EXIF 信息为什么总返回空?
因为 Go 标准库不支持 EXIF,必须用第三方包,且常见错误是没检查文件是否真有 EXIF 数据或误读了缩略图段。很多照片(尤其是手机直出、微信转发、截图)压根没嵌入完整 EXIF,exif.Read 会静默返回 nil 或部分字段为空,不是代码写错了。
- 用
github.com/rwcarlsen/goexif/exif(注意是旧版,兼容性好)或更现代的github.com/xor-gate/goexif2/exif,后者支持更多字段但要求 Go 1.16+ - 务必在调用
exif.Decode前用os.Stat确认文件存在且非零大小,再用bytes.HasPrefix检查前几个字节是否为JPEG(0xFF 0xD8),避免对 PNG/HEIC 文件硬解 -
exif.DateTime字段最常用,但它可能不存在;实际应 fallback 到exif.DateTimeOriginal或exif.DateTimeDigitized,三者语义不同:原拍摄时间 > 数码化时间 > 文件修改时间
重命名时怎么安全生成新文件名?
直接拼接字符串 + os.Rename 极易出错——路径含中文、冒号、斜杠,或目标名已存在,或跨磁盘移动失败。golang 不自动处理这些边界,得自己兜底。
- 用
filepath.Base和filepath.Dir拆分路径,新文件名只操作 basename,保留原目录结构 - 时间格式建议用
time.format("20060102_150405")(Go 唯一固定 layout),避免:和空格;中文系统下还要用strings.map过滤掉 windows 不允许的字符(: " / | ? *) - 重命名前必须检查目标路径是否存在:
os.Stat(newPath),若存在则加序号后缀(如_1),而不是覆盖——相册文件一旦覆盖就不可逆
批量处理大量照片时卡住或崩溃?
默认串行读取+解析+重命名,1000 张照片可能耗时数分钟,且内存暴涨(每张图加载进内存解 EXIF)。问题不在逻辑,而在 IO 和并发控制没做。
- 不要一次性
filepath.Glob("*.jpg")后全塞进内存;改用filepath.WalkDir流式遍历,边发现边处理 - 用带缓冲的 channel 控制并发数(比如
sem := make(chan Struct{}, 4)),每次 goroutine 启动前sem ,结束时 <code>,避免打开太多文件句柄触发 <code>too many open files - EXIF 解析是 CPU 密集型,但 I/O 更慢,所以并发 4–8 即可,再多无收益,反而增加调度开销
Windows 下中文路径乱码或权限拒绝?
Go 1.16+ 在 Windows 上默认用 UTF-16 调用系统 API,但某些老旧文件系统(如 FAT32 U 盘)或杀毒软件会拦截重命名操作,报错 Access is denied 或返回乱码路径。
立即学习“go语言免费学习笔记(深入)”;
- 路径一律用
filepath.ToSlash统一为正斜杠,避免反斜杠转义问题;打印调试时用fmt.Printf("%q", path)查看真实字节 - 遇到
permission denied,先检查文件是否被资源管理器预览窗格锁定(关掉「预览窗格」再试),或用lsof(WSL)或Process Explorer查进程占用 - 别依赖
os.Getwd()当基准路径——它可能返回短路径名(C:USERSADMINI~1...),导致后续filepath.Join拼错;显式用os.Executable()或传入绝对路径参数更稳
EXIF 时间字段缺失、跨文件系统移动、中文符号过滤、并发锁粒度——这些不是“功能做完就完事”的点,而是每次运行都可能突然冒出来的具体阻力。绕不开,只能一个个钉死。