Why am I getting an "index out of range" error when base64 encoding a byte array?

huangapple go评论183阅读模式
英文:

Why am I getting an "index out of range" error when base64 encoding a byte array?

问题

将字节数组编码为Base64字节数组时,上述代码会产生运行时的"索引超出范围"错误。如何解决这个问题?

package main

import (
	"fmt"
	"encoding/base64"
)

func main() {
	data := []byte("string of data")
	encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
	base64.StdEncoding.Encode(encodedData, data)
	fmt.Println(encodedData)
}

Playground链接在这里

英文:

When encoding a byte array into a base64 byte array, the below code produces a runtime index out of range error. How can this be resolved?

package main

import (
	"fmt"
	"encoding/base64"
)

func main() {
	data := []byte("string of data")
	var encodedData []byte
	base64.StdEncoding.Encode(encodedData, data)
	fmt.Println(encodedData)
}

Playground here

答案1

得分: 11

错误信息是:

panic: 运行时错误:索引超出范围

goroutine 1 [运行中]:
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
退出状态 2

shell 返回 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 的长度为零,所以你会得到 索引超出范围 的错误。

修复的一种方法是将该行改为:

encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))

这将创建一个大小为第二个参数的数组。Base64 编码的数据比输入数据更大,因此需要使用 base64.StdEncoding.EncodedLen()

然而,这并不是最好的修复方法。文档 中提到:

> 对于大型数据流的单个块,不适合使用 Encode。应该使用 NewEncoder()。

将代码重写为使用 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)

英文:

The error is:

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

If we look at /usr/lib/go/src/encoding/base64/base64.go line 113, we see (abbreviated):

n := (len(src) / 3) * 3
for si &lt; n {
    // [..]
    dst[di+0] = enc.encode[val&gt;&gt;18&amp;0x3F]
    dst[di+0] = enc.encode[val&gt;&gt;18&amp;0x3F]
    dst[di+1] = enc.encode[val&gt;&gt;12&amp;0x3F]
    // [..]
}

In other words, this function directly sets the index of dst. The length of var encodedData []byte is zero, so you get the index out of range error.

One way to fix it would be to change the line to:

encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))

Which will make an array of the size in the second argument. Base64 encoded data is larger than the input, hence the base64.StdEncoding.EncodedLen().

However, this is hardly the best way to fix it. The documentation mentions:

> Encode is not appropriate for use on individual blocks of a large data stream. Use NewEncoder() instead.

Rewriting the code to NewEncoder() looks like:

func main() {
    data := []byte(&quot;string of data&quot;)

    encodedData := &amp;bytes.Buffer{}
    encoder := base64.NewEncoder(base64.StdEncoding, encodedData)
    defer encoder.Close()
    encoder.Write(data)

    fmt.Println(encodedData)
}

There also some other useful functions, such as EncodeToString() which make the above a bit shorter and more convenient: encodedData := base64.StdEncoding.EncodeToString(data).

答案2

得分: 4

为输出分配空间。例如,

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

英文:

Allocate space for the output. For example,

package main

import (
	&quot;encoding/base64&quot;
	&quot;fmt&quot;
)

func main() {
	data := []byte(&quot;string of data&quot;)
	encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
	base64.StdEncoding.Encode(encodedData, data)
	fmt.Println(encodedData)
}

Output:

[99 51 82 121 97 87 53 110 73 71 57 109 73 71 82 104 100 71 69 61]

var encodedData []byte is zero bytes. Therefore, index out of range

答案3

得分: 1

因为Encode函数期望dst切片已经分配了正确的长度。

Encode函数使用指定的编码方式对src进行编码,将编码后的结果写入长度为EncodedLen(len(src))的dst切片中。

英文:

Because Encode expects the dst slice to be allocated to the correct length.

> Encode encodes src using the encoding enc, writing
> EncodedLen(len(src)) bytes to dst.

huangapple
  • 本文由 发表于 2017年5月4日 07:31:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/43771601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定