Base64编码/解码导致输出损坏

时间:2017-08-29 20:59:25

标签: go

我正在尝试编写一些base64编码和解码字节切片的便捷包装函数。 (无法理解为什么在stdlib中没有方便地提供它。)

但是这段代码(在playground中):

func b64encode(b []byte) []byte {
    encodedData := &bytes.Buffer{}
    encoder := base64.NewEncoder(base64.URLEncoding, encodedData)
    defer encoder.Close()
    encoder.Write(b)
    return encodedData.Bytes()
}

func b64decode(b []byte) ([]byte, error) {
    dec := base64.NewDecoder(base64.URLEncoding, bytes.NewReader(b))
    buf := &bytes.Buffer{}
    _, err := io.Copy(buf, dec)
    if err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}


func main() {
    b := []byte("hello")
    e := b64encode(b)
    d, err := b64decode(e)
    if err != nil {
        log.Fatalf("could not decode: %s", err)
    }
    fmt.Println(string(d))
}
当我尝试打印时,

生成截断的输出:

hel

发生了什么事?

1 个答案:

答案 0 :(得分:8)

当函数结束时执行defer。那是在评估了return语句之后。

以下作品:https://play.golang.org/p/sYn-W6fZh1

func b64encode(b []byte) []byte {
    encodedData := &bytes.Buffer{}
    encoder := base64.NewEncoder(base64.URLEncoding, encodedData)
    encoder.Write(b)
    encoder.Close()
    return encodedData.Bytes()
}

话虽如此,如果真的全部都在内存中,你可以完全避免创建一个编码器。相反,你可以做类似的事情:

func b64encode(b []byte) []byte {
    ret := make([]byte, base64.URLEncoding.EncodedLen(len(b)))
    base64.URLEncoding.Encode(ret, b)
    return ret
}

这样做的额外好处是它更有效率,因为它只需要分配一次。它还允许您不再忽略WriteClose方法中的错误。