最简单方法是直接用os.WriteFile保存图片原始字节;需确保文件后缀与实际格式一致、权限用0644、目标目录存在,且无需解码再编码。

用 os.WriteFile 直接保存 []byte 图片数据最简单
Go 中图片解码后通常得到 *image.Image,但写文件不需要先转成 *image.Image —— 如果你手头已经是原始字节(比如从 HTTP body、数据库或内存缓存读来的 JPEG/PNG 二进制),直接保存即可。os.WriteFile 是最轻量、无编码开销的方式。
- 适用场景:已知图片是完整、合法的二进制流(如
http.Get返回的resp.Body未被读取破坏) - 不推荐用于「自己用
image/png.Encode生成」的场景——那是另一条路径 - 注意权限:目标目录必须存在且可写,否则报
open xxx: no such file or directory
示例:
data := []byte{0xff, 0xd8, 0xff, ...} // 实际是 JPEG header + data
err := os.WriteFile("output.jpg", data, 0644)
if err != nil {
log.Fatal(err)
}
用 image/png.Encode 或 image/jpeg.Encode 从 *image.Image 编码写入
当你有解码后的图像对象(比如调用 image.Decode 得到的 img),需要改尺寸、加水印、转格式再保存时,必须走编码器路径。不同格式对应不同包,参数行为也有差异。
-
image/png.Encode不接受质量参数;image/jpeg.Encode支持jpeg.Options{Quality: 90} - 务必传入带写权限的
*os.File或bytes.Buffer,不能传字符串路径 - 常见错误:
invalid argument多因传了只读文件句柄,或img == nil(解码失败未检查)
示例(JPEG 带质量控制):
立即学习“go语言免费学习笔记(深入)”;
f, _ := os.Create("out.jpg")
defer f.Close()
opts := jpeg.Options{Quality: 85}
err := jpeg.Encode(f, img, &opts)
if err != nil {
log.Fatal(err) // 可能是 "invalid image format" 或 "invalid JPEG quality"
}
内存中拼接多张图再写入?别用 bytes.Buffer 存整个大图
如果操作的是高分辨率图(比如 4K 截图、扫描件),把整张图 load 进 bytes.Buffer 再写,容易触发 GC 压力或 OOM。更稳的做法是用 io.Pipe 或直接流式写入文件句柄。
-
bytes.Buffer适合小图(os.File +io.Copy - 若需在写入前加 header(如 HTTP multipart boundary),用
io.MultiWriter更可控 - 注意:PNG 编码器内部会 buffer 全图,JPEG 则支持逐行编码(但标准库没暴露该能力)
写入失败但没报错?检查 file.Close() 是否被忽略
Go 的文件写入是缓冲的,os.WriteFile 自动处理 close,但用 os.Create + Encode 路径时,如果忘了 file.Close(),可能数据滞留在内核缓冲区,文件看似“空”或“截断”——尤其在程序 panic 或提前 exit 时。
- 永远用
defer f.Close(),不要依赖 GC 关闭文件 - 检查文件大小:写完立刻
fi, _ := f.Stat(); fi.Size(),确认非 0 - Windows 下还可能出现“文件被占用”导致 close 失败,错误信息是
The process cannot access the file because it is being used by another process
实际项目里,最常漏掉的就是 close,而不是 encode 逻辑本身。


















