【问题标题】:Closing gzip writer in defer causes data loss在 defer 中关闭 gzip writer 会导致数据丢失
【发布时间】:2020-03-30 03:31:43
【问题描述】:

我用golang gzip.NewWriter 压缩切片,defer Close() 关闭writer。但是从压缩数据中读取时,它将返回unexpected EOF。代码是:

func main() {

    a := []byte{'a', 'b', 'c', 'd', 'e', 'f'}
    zippedData, err := zipData(a)
    if err != nil {
        panic(err)
    }

    unzippedData, err := unzipData(zippedData)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v\n", unzippedData)

}


zip函数为:

func zipData(originData []byte) ([]byte, error) {
    var bf bytes.Buffer
    gw := gzip.NewWriter(&bf)

    defer gw.Close()

    _, err := gw.Write(originData)
    if err != nil {
        return nil, errors.New(fmt.Sprintf("gzip data err: %v", err))
    }

    err = gw.Flush()
    if err != nil {
        return nil, err
    }
    // if I rm 'defer gw.Close()' and call 'gw.Close()' here, it'll be ok

    logs.Debug("before gzip len: %v", len(originData))
    logs.Debug("gzip len: %v", bf.Len())
    return bf.Bytes(), nil
}

上面的zip函数使用defer gw.Close()来关闭gw。

解压函数为:

func unzipData(zippedData []byte) ([]byte, error) {
    dst := make([]byte, len(zippedData))
    copy(dst, zippedData)

    reader, err := gzip.NewReader(bytes.NewBuffer(dst))
    if err != nil {
        return nil, errors.New(fmt.Sprintf("unzip err :%v", err))
    }

    defer reader.Close()

    data, err := ioutil.ReadAll(reader)
    if err != nil {
        return nil, errors.New(fmt.Sprintf("read err :%v", err))
    }
    return data, err
}

为什么defer gw.Close() 案例unexpected EOF

【问题讨论】:

    标签: go


    【解决方案1】:

    使用 defer,您会丢失 gzip 页脚。根据Close 文档:

    Close 通过将任何未写入的数据刷新到底层 io.Writer 并写入 GZIP 页脚来关闭 Writer。它不会关闭底层的 io.Writer。

    因此,即使Flush 刷新任何缓冲数据,它也不会写入页脚。使用延迟关闭,您将获得不包含页脚的字节数组并将其返回,然后将页脚写入输出。

    在返回之前关闭 writer。

    【讨论】:

      【解决方案2】:

      对于defergw.Close() 在 return 语句中的 bf.Bytes() 调用之后运行。为了确保返回完整的内容,您应该在尝试从缓冲区读取字节之前显式调用gw.Close

      最简单的代码修复方法是将Flush 调用替换为Close 调用。 Flush 是在你没有写完的时候使用的,但在你的情况下你已经完成了压缩,所以调用Close 就足够了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-27
        • 1970-01-01
        相关资源
        最近更新 更多