gzip Reader.Close 有什么意义?

1 gzip file go

如果我有这样的程序,它会按预期失败(在 Windows 上):

package main

import (
   "fmt"
   "os"
)

func main() {
   old := "go1.16.5.src.tar.gz"
   os.Open(old)
   err := os.Rename(old, "new.tar.gz")
   // The process cannot access the file because it is being used by another process.
   fmt.Println(err)
}
Run Code Online (Sandbox Code Playgroud)

但是这个程序成功了:

package main

import (
   "compress/gzip"
   "os"
)

func main() {
   old := "go1.16.5.src.tar.gz"
   f, err := os.Open(old)
   if err != nil {
      panic(err)
   }
   gzip.NewReader(f)
   f.Close()
   os.Rename(old, "new.tar.gz")
}
Run Code Online (Sandbox Code Playgroud)

即使我没有关闭 gzip 阅读器。我的问题是:关闭 gzip 阅读器有什么意义?如果你不这样做,会发生什么“坏事”?我认为一个可能的原因是http#Response.Body[1],因为如果响应包含Content-Encoding: gzip,那么 Go 会自动将 Body 包裹在gzip.Reader. 如果是这种情况,则需要一个 Close 方法,因为 Body 是 a io.ReadCloser,它必须有一个ReadandClose方法。但是gzip#Reader.Close具体说它不会关闭底层读者:

Close 关闭阅读器。它不会关闭底层 io.Reader。

所以直接用 gzip Reader 包装 Body 会很糟糕,因为 Body 在 Close 时会保持打开状态。源代码确认他们使用自定义 gzip 类型 [2]。有趣的是,这种类型 [3] 上的 Close 方法关闭了底层阅读器,但不会费心关闭 gzip 阅读器,即使使用defer. 所以我认为在一般情况下省略使用 gzip Reader Close 是安全的。

  1. https://golang.org/pkg/net/http#Response.Body
  2. https://github.com/golang/go/blob/go1.16.5/src/net/http/transport.go#L2187
  3. https://github.com/golang/go/blob/go1.16.5/src/net/http/transport.go#L2831-L2833

Cer*_*món 6

目前没有理由打电话Close(),但将来可能会改变。

Close()方法最初用于拆除deflater使用的后台goroutine。后台 goroutine 已在2011 年 6 月的更改列表中删除。

CL 的作者在对 CL的评论中写道:

Close 用于拆除与 reader 关联的 goroutine,但现在没有了。可能 Close 会完全消失,但那是一个单独的 CL。

在 Go 1 版本中引入兼容性保证Close()之前,他们从未考虑删除该方法。

截至 2020 年 6 月,该方法实际上没有做任何事情。解压器遇到的任何错误都将从该Close()方法返回。错误也会从Read()应用程序读取到流的末尾返回,因此无需调用Close()即可获取错误。