无需额外分配即可解码base64

时间:2020-01-09 02:48:38

标签: go

我正在尝试解码非常大的base64编码的字符串,可能以兆字节为单位。我想对base64进行解码,而不分配类似大小的输出数组。我想对字符串进行解码,然后重新使用输入字符串的基础存储。

有可能吗?

2 个答案:

答案 0 :(得分:3)

为什么要使用base64编码的不可变string?从[]byte转换为string是浪费的。您应该具有以base64编码的可变[]byte

例如,

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    enc := base64.StdEncoding

    // Test data
    b := make([]byte, 16)
    for i := range b {
        b[i] = byte(i)
    }
    fmt.Println(len(b), b)
    b64 := make([]byte, enc.EncodedLen(len(b)))
    enc.Encode(b64, b)

    // Decode base64 without extra array allocations
    fmt.Printf("%d %q\n", len(b64), b64)
    d := b64
    n, err := enc.Decode(d, b64)
    d = d[:n:n]
    if err != nil {
        panic(err)
    }
    fmt.Println(len(d), d)
}

游乐场:https://play.golang.org/p/BfyaXjv_vwS

输出:

16 [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
24 "AAECAwQFBgcICQoLDA0ODw=="
16 [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]

注意:缓冲区的安全共享可能取决于实现。编写测试以确保它继续安全。

答案 1 :(得分:-2)

是的,可以使用不安全的代码。正如已经建议的,寻找另一种选择,但是...

也许您被卡住了,因为您得到了一个字符串(您知道该字符串不在只读内存中),并且您无法访问字节片。如果您小心一点,可以修改类似以下的字符串:

// build a string (string literals are kept in read-only memory)
sb := strings.Builder{}
sb.WriteString("abc")
s := sb.String()

b := *(*struct {p *[999999999]byte; length int})(unsafe.Pointer(&s))
// Be very careful not to write past the end of the string
b.p[b.length-1]++  // modify the last byte

同样,我不能过分强调不安全的代码是危险的,因此您需要非常小心。例如,请确保您不要在字符串的末尾写过文字,并理解为什么字符串是不可变的。