我正在嘗試使用compress/gzip. 每當我在筆記本電腦上壓縮長度超過 2^15 的切片時,解壓后索引為 2^15 或更大的每個字節都設置為 0。當我在我的研究集群上運行相同的代碼時,它也會中斷。調用go version我的筆記本電腦打?。? go versiongo version go1.5 darwin/amd64調用go version集群打?。? go versiongo version go1.3.3 linux/amd64下面是我寫的一個演示測試文件。它生成不同長度的隨機切片,壓縮它們,然后解壓縮它們。它檢查沒有調用返回錯誤,并檢查壓縮和解壓縮的切片是否相同:package compressimport ( "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()) }當我運行這個測試時,我得到以下輸出:$ 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] = 0FAILexit status 1有誰知道這里發生了什么?我是否以某種方式濫用了該軟件包?如果我沒有提供足夠的信息,請告訴我。
1 回答

慕絲7291255
TA貢獻1859條經驗 獲得超6個贊
問題出在這一行:
reader.Read(out)
不能保證一步Reader.Read()讀取整個out切片。
gzip.Reader.Read()是執行io.Reader.Read()。
引用其文檔(“一般合同”):
Read(p []byte) (n int, err error)
Read 將最多len(p) 個字節讀入 p。
不保證Reader.Read()會一直讀取直到out被填滿,如果實現需要,它可能會在更少的字節處停止(即使沒有達到 EOF)。如果您傳遞“大”切片,則在實現的內部緩存耗盡時很容易發生這種情況。Read()返回讀取的字節數(和error),您可以使用它來檢查是否讀取了完整的切片。
或者更好的是,您可以使用它io.ReadFull()來確保out已完全閱讀:
if _, err = io.ReadFull(reader, out); err != nil {
t.Errorf("Error reading full out slice:", err)
}
通過應用此更改,您的測試將通過。
- 1 回答
- 0 關注
- 142 瀏覽
添加回答
舉報
0/150
提交
取消