使用 Go 的 base64.StdEncoding.Decode() 方法:如何选择目标字节切片的大小?
Using Go's base64.StdEncoding.Decode() method: how to choose the size of the destination byte slice?
我想使用 Decode
(https://golang.org/pkg/encoding/base64/#Encoding.Decode) 来解码一段字节并且想知道,给定这个方法签名,
func (enc *Encoding) Decode(dst, src []byte) (n int, err error)
如何选择 dst
字节片的大小刚好足以捕获输出。例如,这个片段(改编自 https://golang.org/pkg/encoding/base64/#Encoding.DecodeString)
package main
import (
"encoding/base64"
"fmt"
)
func main() {
str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
dst := make([]byte, 1024)
_, err := base64.StdEncoding.Decode(dst, []byte(str))
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("%s\n", dst)
}
打印
some data with and
但是,如果我选择 dst
的大小太小(例如 0
),我会得到一个 index out of range
恐慌:
panic: runtime error: index out of range
goroutine 1 [running]:
encoding/base64.(*Encoding).decodeQuantum(0xc000084000, 0x1193018, 0x0, 0x0, 0xc000080f30, 0x20, 0x20, 0x4, 0x10, 0x10, ...)
/usr/local/Cellar/go@1.12/1.12.12/libexec/src/encoding/base64/base64.go:352 +0x567
encoding/base64.(*Encoding).Decode(0xc000084000, 0x1193018, 0x0, 0x0, 0xc000080f30, 0x20, 0x20, 0xc000080f38, 0x105779d, 0x10b16e0)
/usr/local/Cellar/go@1.12/1.12.12/libexec/src/encoding/base64/base64.go:500 +0x5aa
main.main()
/Users/kurt/Documents/Scratch/base64_decode.go:11 +0xb4
exit status 2
如何根据 src
的大小选择 dst
的大小来可靠地解码输入?
您应该使用 base64.DecodedLen
找到解码输入所需的最大大小,然后使用从 Decode
返回的 n
找出它真正写入了多长时间那片。
在jps's comment and reading up at https://en.wikipedia.org/wiki/Base64之后,由于输入是8位字节编码,而输出是6位(radix-64)字节,所以输出需要8/6 = 4/3倍输入的大小。所以这应该有效:
package main
import (
"encoding/base64"
"fmt"
)
func main() {
str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
dst := make([]byte, len(str)*len(str)/base64.StdEncoding.DecodedLen(len(str)))
_, err := base64.StdEncoding.Decode(dst, []byte(str))
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("%s\n", dst)
}
基于DecodedLen()
的执行,一般情况下returns输入的长度乘以3/4:
// DecodedLen returns the maximum length in bytes of the decoded data
// corresponding to n bytes of base64-encoded data.
func (enc *Encoding) DecodedLen(n int) int {
if enc.padChar == NoPadding {
// Unpadded data may end with partial block of 2-3 characters.
return n * 6 / 8
}
// Padded base64 should always be a multiple of 4 characters in length.
return n / 4 * 3
}
不过,最后我只是将输入转换为字符串并使用 DecodeString()
,因为这已经体现了这种逻辑。
我想使用 Decode
(https://golang.org/pkg/encoding/base64/#Encoding.Decode) 来解码一段字节并且想知道,给定这个方法签名,
func (enc *Encoding) Decode(dst, src []byte) (n int, err error)
如何选择 dst
字节片的大小刚好足以捕获输出。例如,这个片段(改编自 https://golang.org/pkg/encoding/base64/#Encoding.DecodeString)
package main
import (
"encoding/base64"
"fmt"
)
func main() {
str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
dst := make([]byte, 1024)
_, err := base64.StdEncoding.Decode(dst, []byte(str))
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("%s\n", dst)
}
打印
some data with and
但是,如果我选择 dst
的大小太小(例如 0
),我会得到一个 index out of range
恐慌:
panic: runtime error: index out of range
goroutine 1 [running]:
encoding/base64.(*Encoding).decodeQuantum(0xc000084000, 0x1193018, 0x0, 0x0, 0xc000080f30, 0x20, 0x20, 0x4, 0x10, 0x10, ...)
/usr/local/Cellar/go@1.12/1.12.12/libexec/src/encoding/base64/base64.go:352 +0x567
encoding/base64.(*Encoding).Decode(0xc000084000, 0x1193018, 0x0, 0x0, 0xc000080f30, 0x20, 0x20, 0xc000080f38, 0x105779d, 0x10b16e0)
/usr/local/Cellar/go@1.12/1.12.12/libexec/src/encoding/base64/base64.go:500 +0x5aa
main.main()
/Users/kurt/Documents/Scratch/base64_decode.go:11 +0xb4
exit status 2
如何根据 src
的大小选择 dst
的大小来可靠地解码输入?
您应该使用 base64.DecodedLen
找到解码输入所需的最大大小,然后使用从 Decode
返回的 n
找出它真正写入了多长时间那片。
在jps's comment and reading up at https://en.wikipedia.org/wiki/Base64之后,由于输入是8位字节编码,而输出是6位(radix-64)字节,所以输出需要8/6 = 4/3倍输入的大小。所以这应该有效:
package main
import (
"encoding/base64"
"fmt"
)
func main() {
str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
dst := make([]byte, len(str)*len(str)/base64.StdEncoding.DecodedLen(len(str)))
_, err := base64.StdEncoding.Decode(dst, []byte(str))
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("%s\n", dst)
}
基于DecodedLen()
的执行,一般情况下returns输入的长度乘以3/4:
// DecodedLen returns the maximum length in bytes of the decoded data
// corresponding to n bytes of base64-encoded data.
func (enc *Encoding) DecodedLen(n int) int {
if enc.padChar == NoPadding {
// Unpadded data may end with partial block of 2-3 characters.
return n * 6 / 8
}
// Padded base64 should always be a multiple of 4 characters in length.
return n / 4 * 3
}
不过,最后我只是将输入转换为字符串并使用 DecodeString()
,因为这已经体现了这种逻辑。