Golang中哪种"out.Close"实现方式更优?
Golang中哪种"out.Close"实现方式更优? 大家好
哪种"out.Close"对语言性能更好?(如你所知,"defer"在循环中效果不佳)
func SaveAvatar() string{
var size [6][2]uint
size[0] = [2]uint{75, 30}
size[1] = [2]uint{100, 40}
for _, v := range size {
out, err := os.Create("pic/ava/" + "u" + "_" +
"150000" + "_" + "123" + "_" + strconv.Itoa(int(v[0])) + "." +"JPG")
if err != nil {
return "R_FAILED"
}
//jpeg.Encode(out, Avatar, nil)
err =os.Remove("Av" + "_" + strconv.Itoa(int(v[0])) + "." + "JPG")
if err != nil {
return "R_FAILED"
}
out.Close()
}
return "R_Succ"
}
func SaveAvatar() string{
var size [6][2]uint
size[0] = [2]uint{75, 30}
size[1] = [2]uint{100, 40}
for _, v := range size {
out, err := os.Create("pic/ava/" + "u" + "_" +
"150000" + "_" + "123" + "_" + strconv.Itoa(int(v[0])) + "." +"JPG")
if err != nil {
out.Close()
return "R_FAILED"
}
//jpeg.Encode(out, Avatar, nil)
err =os.Remove("Av" + "_" + strconv.Itoa(int(v[0])) + "." + "JPG")
if err != nil {
out.Close()
return "R_FAILED"
}
out.Close()
}
return "R_Succ"
}
这里是代码演示:
https://play.golang.org/p/49u1nJYi8xU
提前感谢。
更多关于Golang中哪种"out.Close"实现方式更优?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
4 回复
更多关于Golang中哪种"out.Close"实现方式更优?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
out, err := os.Create("pic/ava/" + "u" + "_" + "150000" + "_" + "123" + "_" + strconv.Itoa(int(v[0])) + "." +"JPG")
可以重写为
out, err := os.Create(fmt.Sprintf("pic/ava/u150000_123_%s.JPG", v[0]))
这样稍微简短一些,并且更容易看出用于 os.Create 的路径。对于 os.Unlink 的参数也是同样的处理方式。
你好 Hamed,
有两点需要注意:
- 如果打开(或创建)文件失败,那么就没有需要关闭的文件。你不需要调用
out.Close(),因为此时out是nil。 - 你只需要在文件使用完毕后关闭它。所以请将
os.Close()紧接在jpeg.Encode()之后调用。
在循环中处理文件关闭时,第二种实现方式更优,因为它确保了在所有错误返回路径上都正确关闭文件句柄。
第一种实现的问题在于当os.Create或os.Remove出错时直接返回,没有关闭已经创建的文件句柄,这会导致文件描述符泄漏。
以下是改进的实现示例:
func SaveAvatar() string {
sizes := [][2]uint{
{75, 30},
{100, 40},
// ... 其他尺寸
}
for _, size := range sizes {
filename := fmt.Sprintf("pic/ava/u_150000_123_%d.JPG", size[0])
out, err := os.Create(filename)
if err != nil {
return "R_FAILED"
}
// 使用defer在函数退出时关闭,但需要包装在匿名函数中
func() {
defer out.Close()
// jpeg.Encode(out, Avatar, nil)
removeFilename := fmt.Sprintf("Av_%d.JPG", size[0])
if err := os.Remove(removeFilename); err != nil {
return
}
}()
}
return "R_Succ"
}
或者更明确的错误处理版本:
func SaveAvatar() string {
sizes := [][2]uint{
{75, 30},
{100, 40},
}
for _, size := range sizes {
filename := fmt.Sprintf("pic/ava/u_150000_123_%d.JPG", size[0])
out, err := os.Create(filename)
if err != nil {
return "R_FAILED"
}
// 处理编码逻辑
// if err := jpeg.Encode(out, Avatar, nil); err != nil {
// out.Close()
// return "R_FAILED"
// }
removeFilename := fmt.Sprintf("Av_%d.JPG", size[0])
if err := os.Remove(removeFilename); err != nil {
out.Close()
return "R_FAILED"
}
if err := out.Close(); err != nil {
return "R_FAILED"
}
}
return "R_Succ"
}
第二种方式的优势在于:
- 确保所有错误路径都关闭文件
- 避免文件描述符泄漏
- 代码执行路径清晰
在性能敏感的场景中,还可以考虑批量处理文件操作或使用sync.Pool来优化资源管理。


