将 int 数组转换为字节数组,压缩然后反转
Convert int array to byte array, compress it then reverse it
我有一个大型 int 数组,我想保留在文件系统上。我的理解是存储这样的东西的最好方法是使用 gob package to convert it to a byte array and then to compress it with gzip。
当我再次需要它时,我会反转这个过程。我很确定我正确地存储了它,但是使用 EOF 恢复它失败了。长话短说,我在下面有一些示例代码可以演示该问题。 (游乐场 link 此处 https://play.golang.org/p/v4rGGeVkLNh)。
我不相信需要 gob,但是阅读它似乎将它存储为字节数组比 int 数组更有效,但这可能不是真的。谢谢!
package main
import (
"bufio"
"bytes"
"compress/gzip"
"encoding/gob"
"fmt"
)
func main() {
arry := []int{1, 2, 3, 4, 5}
//now gob this
var indexBuffer bytes.Buffer
writer := bufio.NewWriter(&indexBuffer)
encoder := gob.NewEncoder(writer)
if err := encoder.Encode(arry); err != nil {
panic(err)
}
//now compress it
var compressionBuffer bytes.Buffer
compressor := gzip.NewWriter(&compressionBuffer)
compressor.Write(indexBuffer.Bytes())
defer compressor.Close()
//<--- I think all is good until here
//now decompress it
buf := bytes.NewBuffer(compressionBuffer.Bytes())
fmt.Println("byte array before unzipping: ", buf.Bytes())
if reader, err := gzip.NewReader(buf); err != nil {
fmt.Println("gzip failed ", err)
panic(err)
} else {
//now ungob it...
var intArray []int
decoder := gob.NewDecoder(reader)
defer reader.Close()
if err := decoder.Decode(&intArray); err != nil {
fmt.Println("gob failed ", err)
panic(err)
}
fmt.Println("final int Array content: ", intArray)
}
}
您正在使用 bufio.Writer
,顾名思义, 缓冲区 写入其中的字节。这意味着如果你正在使用它,你必须 flush 它以确保缓冲数据到达底层编写器:
writer := bufio.NewWriter(&indexBuffer)
encoder := gob.NewEncoder(writer)
if err := encoder.Encode(arry); err != nil {
panic(err)
}
if err := writer.Flush(); err != nil {
panic(err)
}
尽管完全没有必要使用 bufio.Writer
,因为您已经在写入 in-memory 缓冲区 (bytes.Buffer
),所以请跳过它,直接写入 bytes.Buffer
(所以你甚至不必冲洗):
var indexBuffer bytes.Buffer
encoder := gob.NewEncoder(&indexBuffer)
if err := encoder.Encode(arry); err != nil {
panic(err)
}
下一个错误是如何关闭 gzip 流:
defer compressor.Close()
此延迟关闭只会在封闭函数(main()
函数)returns 时发生,不会早一秒。但那时你已经想读取压缩数据,但它可能仍位于 gzip.Writer
的内部缓存中,而不是 compressionBuffer
,因此你显然无法从 compressionBuffer
。不使用 defer
:
关闭 gzip 流
if err := compressor.Close(); err != nil {
panic(err)
}
通过这些更改,您的程序运行并输出(在 Go Playground 上尝试):
byte array before unzipping: [31 139 8 0 0 0 0 0 0 255 226 249 223 200 196 200 244 191 137 129 145 133 129 129 243 127 19 3 43 19 11 27 7 23 32 0 0 255 255 110 125 126 12 23 0 0 0]
final int Array content: [1 2 3 4 5]
旁注:buf := bytes.NewBuffer(compressionBuffer.Bytes())
——这个buf
也是完全没有必要的,你可以开始解码compressionBuffer
本身,你可以从中读取数据之前写入它。
您可能已经注意到,压缩数据比初始压缩数据大得多。有几个原因:两个 encoding/gob
and compress/gzip
流都有很大的开销,并且它们(可能)只会在更大范围内使输入更小(5 int 数字不符合此条件)。
请检查相关问题:
对于小数组,也可以考虑variable-length encoding, see binary.PutVarint()
。
我有一个大型 int 数组,我想保留在文件系统上。我的理解是存储这样的东西的最好方法是使用 gob package to convert it to a byte array and then to compress it with gzip。 当我再次需要它时,我会反转这个过程。我很确定我正确地存储了它,但是使用 EOF 恢复它失败了。长话短说,我在下面有一些示例代码可以演示该问题。 (游乐场 link 此处 https://play.golang.org/p/v4rGGeVkLNh)。 我不相信需要 gob,但是阅读它似乎将它存储为字节数组比 int 数组更有效,但这可能不是真的。谢谢!
package main
import (
"bufio"
"bytes"
"compress/gzip"
"encoding/gob"
"fmt"
)
func main() {
arry := []int{1, 2, 3, 4, 5}
//now gob this
var indexBuffer bytes.Buffer
writer := bufio.NewWriter(&indexBuffer)
encoder := gob.NewEncoder(writer)
if err := encoder.Encode(arry); err != nil {
panic(err)
}
//now compress it
var compressionBuffer bytes.Buffer
compressor := gzip.NewWriter(&compressionBuffer)
compressor.Write(indexBuffer.Bytes())
defer compressor.Close()
//<--- I think all is good until here
//now decompress it
buf := bytes.NewBuffer(compressionBuffer.Bytes())
fmt.Println("byte array before unzipping: ", buf.Bytes())
if reader, err := gzip.NewReader(buf); err != nil {
fmt.Println("gzip failed ", err)
panic(err)
} else {
//now ungob it...
var intArray []int
decoder := gob.NewDecoder(reader)
defer reader.Close()
if err := decoder.Decode(&intArray); err != nil {
fmt.Println("gob failed ", err)
panic(err)
}
fmt.Println("final int Array content: ", intArray)
}
}
您正在使用 bufio.Writer
,顾名思义, 缓冲区 写入其中的字节。这意味着如果你正在使用它,你必须 flush 它以确保缓冲数据到达底层编写器:
writer := bufio.NewWriter(&indexBuffer)
encoder := gob.NewEncoder(writer)
if err := encoder.Encode(arry); err != nil {
panic(err)
}
if err := writer.Flush(); err != nil {
panic(err)
}
尽管完全没有必要使用 bufio.Writer
,因为您已经在写入 in-memory 缓冲区 (bytes.Buffer
),所以请跳过它,直接写入 bytes.Buffer
(所以你甚至不必冲洗):
var indexBuffer bytes.Buffer
encoder := gob.NewEncoder(&indexBuffer)
if err := encoder.Encode(arry); err != nil {
panic(err)
}
下一个错误是如何关闭 gzip 流:
defer compressor.Close()
此延迟关闭只会在封闭函数(main()
函数)returns 时发生,不会早一秒。但那时你已经想读取压缩数据,但它可能仍位于 gzip.Writer
的内部缓存中,而不是 compressionBuffer
,因此你显然无法从 compressionBuffer
。不使用 defer
:
if err := compressor.Close(); err != nil {
panic(err)
}
通过这些更改,您的程序运行并输出(在 Go Playground 上尝试):
byte array before unzipping: [31 139 8 0 0 0 0 0 0 255 226 249 223 200 196 200 244 191 137 129 145 133 129 129 243 127 19 3 43 19 11 27 7 23 32 0 0 255 255 110 125 126 12 23 0 0 0]
final int Array content: [1 2 3 4 5]
旁注:buf := bytes.NewBuffer(compressionBuffer.Bytes())
——这个buf
也是完全没有必要的,你可以开始解码compressionBuffer
本身,你可以从中读取数据之前写入它。
您可能已经注意到,压缩数据比初始压缩数据大得多。有几个原因:两个 encoding/gob
and compress/gzip
流都有很大的开销,并且它们(可能)只会在更大范围内使输入更小(5 int 数字不符合此条件)。
请检查相关问题:
对于小数组,也可以考虑variable-length encoding, see binary.PutVarint()
。