为什么在使用 base64 编码字节数组时会出现 "index out of range" 错误?
Why am I getting an "index out of range" error when base64 encoding a byte array?
将字节数组编码为 base64 字节数组时,以下代码会产生运行时 index out of range
错误。如何解决?
package main
import (
"fmt"
"encoding/base64"
)
func main() {
data := []byte("string of data")
var encodedData []byte
base64.StdEncoding.Encode(encodedData, data)
fmt.Println(encodedData)
}
为输出分配 space。例如,
package main
import (
"encoding/base64"
"fmt"
)
func main() {
data := []byte("string of data")
encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(encodedData, data)
fmt.Println(encodedData)
}
输出:
[99 51 82 121 97 87 53 110 73 71 57 109 73 71 82 104 100 71 69 61]
var encodedData []byte
是零字节。因此,index out of range
因为 Encode 期望 dst
切片被分配到正确的长度。
Encode encodes src using the encoding enc, writing
EncodedLen(len(src)) bytes to dst.
错误是:
panic: runtime error: index out of range
goroutine 1 [running]:
encoding/base64.(*Encoding).Encode(0xc420056000, 0x0, 0x0, 0x0, 0xc42003bf30, 0xe, 0x20)
/usr/lib/go/src/encoding/base64/base64.go:113 +0x27b
main.main()
/home/martin/a.go:11 +0x9b
exit status 2
shell returned 1
如果我们查看 /usr/lib/go/src/encoding/base64/base64.go
第 113 行,我们会看到(缩写):
n := (len(src) / 3) * 3
for si < n {
// [..]
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+1] = enc.encode[val>>12&0x3F]
// [..]
}
也就是说,这个函数直接设置了dst
的索引。 var encodedData []byte
的长度为零,因此出现 index out of range
错误。
修复它的一种方法是将行更改为:
encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
这将生成第二个参数中大小的数组。 Base64 编码数据大于输入,因此 base64.StdEncoding.EncodedLen()
.
但是,这并不是修复它的最佳方法。 The documentation 提及:
Encode is not appropriate for use on individual blocks of a large data stream. Use NewEncoder() instead.
将代码重写为 NewEncoder()
看起来像:
func main() {
data := []byte("string of data")
encodedData := &bytes.Buffer{}
encoder := base64.NewEncoder(base64.StdEncoding, encodedData)
defer encoder.Close()
encoder.Write(data)
fmt.Println(encodedData)
}
还有一些其他有用的函数,例如EncodeToString()
,使上面的代码更短更方便:encodedData := base64.StdEncoding.EncodeToString(data)
.
将字节数组编码为 base64 字节数组时,以下代码会产生运行时 index out of range
错误。如何解决?
package main
import (
"fmt"
"encoding/base64"
)
func main() {
data := []byte("string of data")
var encodedData []byte
base64.StdEncoding.Encode(encodedData, data)
fmt.Println(encodedData)
}
为输出分配 space。例如,
package main
import (
"encoding/base64"
"fmt"
)
func main() {
data := []byte("string of data")
encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(encodedData, data)
fmt.Println(encodedData)
}
输出:
[99 51 82 121 97 87 53 110 73 71 57 109 73 71 82 104 100 71 69 61]
var encodedData []byte
是零字节。因此,index out of range
因为 Encode 期望 dst
切片被分配到正确的长度。
Encode encodes src using the encoding enc, writing EncodedLen(len(src)) bytes to dst.
错误是:
panic: runtime error: index out of range
goroutine 1 [running]:
encoding/base64.(*Encoding).Encode(0xc420056000, 0x0, 0x0, 0x0, 0xc42003bf30, 0xe, 0x20)
/usr/lib/go/src/encoding/base64/base64.go:113 +0x27b
main.main()
/home/martin/a.go:11 +0x9b
exit status 2
shell returned 1
如果我们查看 /usr/lib/go/src/encoding/base64/base64.go
第 113 行,我们会看到(缩写):
n := (len(src) / 3) * 3
for si < n {
// [..]
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+1] = enc.encode[val>>12&0x3F]
// [..]
}
也就是说,这个函数直接设置了dst
的索引。 var encodedData []byte
的长度为零,因此出现 index out of range
错误。
修复它的一种方法是将行更改为:
encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
这将生成第二个参数中大小的数组。 Base64 编码数据大于输入,因此 base64.StdEncoding.EncodedLen()
.
但是,这并不是修复它的最佳方法。 The documentation 提及:
Encode is not appropriate for use on individual blocks of a large data stream. Use NewEncoder() instead.
将代码重写为 NewEncoder()
看起来像:
func main() {
data := []byte("string of data")
encodedData := &bytes.Buffer{}
encoder := base64.NewEncoder(base64.StdEncoding, encodedData)
defer encoder.Close()
encoder.Write(data)
fmt.Println(encodedData)
}
还有一些其他有用的函数,例如EncodeToString()
,使上面的代码更短更方便:encodedData := base64.StdEncoding.EncodeToString(data)
.