无法在 Mac OS X 上的 Go 1.5 中 gzip 超过 32768 字节的切片
Cannot gzip slices with more than 32768 bytes in Go 1.5 on Mac OS X
我正在尝试使用 compress/gzip
在 Go 中压缩字节片。每当我在笔记本电脑上压缩长度超过 2^15 的切片时,每个索引为 2^15 或更大的字节在解压缩后都会设置为 0。当我 运行 在我的研究集群上使用相同的代码时,它也会崩溃。
在我的笔记本电脑上调用 go version
打印:
$ go version
go version go1.5 darwin/amd64
在集群上调用 go version
输出:
$ go version
go version go1.3.3 linux/amd64
下面是我写的一个演示测试文件。它生成不同长度的随机切片,压缩它们,然后解压缩它们。它检查没有调用 returns 错误,还检查压缩和解压缩的切片是否相同:
package compress
import (
"bytes"
"compress/gzip"
"math/rand"
"testing"
)
func byteSliceEq(xs, ys []byte) bool {
if len(xs) != len(ys) { return false }
for i := range xs {
if xs[i] != ys[i] { return false }
}
return true
}
func TestGzip(t *testing.T) {
tests := []struct {
n int
}{
{ 1<<10 },
{ 1<<15 },
{ 1<<15 + 1 },
{ 1<<20 },
}
rand.Seed(0)
for i := range tests {
n := tests[i].n
in, out := make([]byte, n), make([]byte, n)
buf := &bytes.Buffer{}
for i := range in { in[i] = byte(rand.Intn(256)) }
writer := gzip.NewWriter(buf)
_, err := writer.Write(in)
if err != nil {
t.Errorf("%d) n = %d: writer.Write() error: %s",
i + 1, n, err.Error())
}
err = writer.Close()
if err != nil {
t.Errorf("%d) n = %d: writer.Close() error: %s",
i + 1, n, err.Error())
}
reader, err := gzip.NewReader(buf)
if err != nil {
t.Errorf("%d) n = %d: gzip.NewReader error: %s",
i + 1, n, err.Error())
}
reader.Read(out)
err = reader.Close()
if err != nil {
t.Errorf("%d) n = %d: reader.Close() error: %s",
i + 1, n, err.Error())
}
if !byteSliceEq(in, out) {
idx := -1
for i := range in {
if in[i] != out[i] {
idx = i
break
}
}
t.Errorf("%d) n = %d: in[%d] = %d, but out[%d] = %d",
i + 1, n, idx, in[idx], idx, out[idx])
}
}
}
当我运行这个测试时,我得到以下输出:
$ go test --run "TestGzip"
--- FAIL: TestGzip (0.12s)
gzip_test.go:77: 3) n = 32769: in[32768] = 78, but out[32768] = 0
gzip_test.go:77: 4) n = 1048576: in[32768] = 229, but out[32768] = 0
FAIL
exit status 1
有人知道这里发生了什么吗?我是否以某种方式滥用了包裹?如果我没有提供足够的信息,请告诉我。
问题出在这一行:
reader.Read(out)
无法保证 Reader.Read()
将一步读取整个 out
切片 。
gzip.Reader.Read()
is to implement io.Reader.Read()
.
引用其文档(“总合同”):
Read(p []byte) (n int, err error)
Read reads up to len(p) bytes into p.
无法保证 Reader.Read()
会读取到 out
被填满,如果实现希望如此,它可能会在更少的字节处停止(即使未达到 EOF)。如果您传递一个“大”切片,如果实现的内部缓存耗尽,则很容易发生这种情况。 Read()
returns 读取的字节数(和一个 error
),您可以使用它来检查是否读取了完整的切片。
或者更好的是,您可以使用 io.ReadFull()
来确保 out
被完整阅读:
if _, err = io.ReadFull(reader, out); err != nil {
t.Errorf("Error reading full out slice:", err)
}
通过应用此更改,您的测试通过。
我正在尝试使用 compress/gzip
在 Go 中压缩字节片。每当我在笔记本电脑上压缩长度超过 2^15 的切片时,每个索引为 2^15 或更大的字节在解压缩后都会设置为 0。当我 运行 在我的研究集群上使用相同的代码时,它也会崩溃。
在我的笔记本电脑上调用 go version
打印:
$ go version
go version go1.5 darwin/amd64
在集群上调用 go version
输出:
$ go version
go version go1.3.3 linux/amd64
下面是我写的一个演示测试文件。它生成不同长度的随机切片,压缩它们,然后解压缩它们。它检查没有调用 returns 错误,还检查压缩和解压缩的切片是否相同:
package compress
import (
"bytes"
"compress/gzip"
"math/rand"
"testing"
)
func byteSliceEq(xs, ys []byte) bool {
if len(xs) != len(ys) { return false }
for i := range xs {
if xs[i] != ys[i] { return false }
}
return true
}
func TestGzip(t *testing.T) {
tests := []struct {
n int
}{
{ 1<<10 },
{ 1<<15 },
{ 1<<15 + 1 },
{ 1<<20 },
}
rand.Seed(0)
for i := range tests {
n := tests[i].n
in, out := make([]byte, n), make([]byte, n)
buf := &bytes.Buffer{}
for i := range in { in[i] = byte(rand.Intn(256)) }
writer := gzip.NewWriter(buf)
_, err := writer.Write(in)
if err != nil {
t.Errorf("%d) n = %d: writer.Write() error: %s",
i + 1, n, err.Error())
}
err = writer.Close()
if err != nil {
t.Errorf("%d) n = %d: writer.Close() error: %s",
i + 1, n, err.Error())
}
reader, err := gzip.NewReader(buf)
if err != nil {
t.Errorf("%d) n = %d: gzip.NewReader error: %s",
i + 1, n, err.Error())
}
reader.Read(out)
err = reader.Close()
if err != nil {
t.Errorf("%d) n = %d: reader.Close() error: %s",
i + 1, n, err.Error())
}
if !byteSliceEq(in, out) {
idx := -1
for i := range in {
if in[i] != out[i] {
idx = i
break
}
}
t.Errorf("%d) n = %d: in[%d] = %d, but out[%d] = %d",
i + 1, n, idx, in[idx], idx, out[idx])
}
}
}
当我运行这个测试时,我得到以下输出:
$ go test --run "TestGzip"
--- FAIL: TestGzip (0.12s)
gzip_test.go:77: 3) n = 32769: in[32768] = 78, but out[32768] = 0
gzip_test.go:77: 4) n = 1048576: in[32768] = 229, but out[32768] = 0
FAIL
exit status 1
有人知道这里发生了什么吗?我是否以某种方式滥用了包裹?如果我没有提供足够的信息,请告诉我。
问题出在这一行:
reader.Read(out)
无法保证 Reader.Read()
将一步读取整个 out
切片 。
gzip.Reader.Read()
is to implement io.Reader.Read()
.
引用其文档(“总合同”):
Read(p []byte) (n int, err error)
Read reads up to len(p) bytes into p.
无法保证 Reader.Read()
会读取到 out
被填满,如果实现希望如此,它可能会在更少的字节处停止(即使未达到 EOF)。如果您传递一个“大”切片,如果实现的内部缓存耗尽,则很容易发生这种情况。 Read()
returns 读取的字节数(和一个 error
),您可以使用它来检查是否读取了完整的切片。
或者更好的是,您可以使用 io.ReadFull()
来确保 out
被完整阅读:
if _, err = io.ReadFull(reader, out); err != nil {
t.Errorf("Error reading full out slice:", err)
}
通过应用此更改,您的测试通过。