我有一个包含gzip压缩字符串的字符串,因此没有文件头,标准compress/gzip
库抛出错误gzip: invalid header
如何在go中解压缩gzip压缩的字符串?
这就是我正在尝试的
nbody := "eNorTk0uSi0BAAjRAoc="
rdata := strings.NewReader(nbody)
r,err := gzip.NewReader(rdata)
log.Println(r)
if err != nil {
log.Fatal(err)
}
s, _ := ioutil.ReadAll(r)
fmt.Println(string(s))
答案 0 :(得分:5)
...我有一个包含gzip压缩字符串的字符串
nbody := "eNorTk0uSi0BAAjRAoc="
这不是“ gzip压缩字符串”。看起来有些需要先解码的base64编码数据。解码后,它也不是gzip,而是zlib-与gzip(使用deflate算法压缩的内容)基本相同,但是文件头不同。因此,尝试使用gzip对其进行解码将无法正常工作。
因此,以下内容将使用您的原始字符串,从base64对其进行解码,然后使用zlib(而非gzip)将其解压缩:
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"io/ioutil"
)
func main() {
b64z := "eNorTk0uSi0BAAjRAoc="
z, _ := base64.StdEncoding.DecodeString(b64z)
r, _ := zlib.NewReader(bytes.NewReader(z))
result, _ := ioutil.ReadAll(r)
fmt.Println(string(result)) // results in "secret"
}
答案 1 :(得分:0)
nobody字符串不是gzip数据。 gzip具有gzip标头。(https://golang.org/src/compress/gzip/gunzip.go?s=1297:1500#L42)
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"log"
)
func main() {
nbody := "eNorTk0uSi0BAAjRAoc="
fmt.Println("original:\t", nbody)
var buf bytes.Buffer
err := gzipWrite(&buf, []byte(nbody))
if err != nil {
log.Fatal(err)
}
fmt.Println("compressed:\t", buf.String())
var buf2 bytes.Buffer
err = gunzipWrite(&buf2, buf.Bytes())
if err != nil {
log.Fatal(err)
}
fmt.Println("decompressed:\t", buf2.String())
}
func gzipWrite(w io.Writer, data []byte) error {
gw, err := gzip.NewWriterLevel(w, gzip.BestSpeed)
defer gw.Close()
gw.Write(data)
return err
}
func gunzipWrite(w io.Writer, data []byte) error {
gr, err := gzip.NewReader(bytes.NewBuffer(data))
defer gr.Close()
data, err = ioutil.ReadAll(gr)
if err != nil {
return err
}
w.Write(data)
return nil
}
答案 2 :(得分:0)
因为如果您在字符串中有真实的 gzip 编码数据并想对其进行解码,那么这个问题一直会出现在 google 上,所以您可以这样做:
import "compress/gzip";
import "bytes";
import "io/ioutil";
...
original := "gzipencodeddata";
reader := bytes.NewReader([]byte(original))
gzreader, e1 := gzip.NewReader(reader);
if(e1 != nil){
fmt.Println(e1); // Maybe panic here, depends on your error handling.
}
output, e2 := ioutil.ReadAll(gzreader);
if(e2 != nil){
fmt.Println(e2);
}
result := string(output);
答案 3 :(得分:-1)
如果输入量较大,则可能要使用流和自定义的解码器链。
其优点是(除了本示例外)编码输入和解码输出都不必驻留在RAM中。
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"io"
"log"
"os"
"strings"
)
const nbody = "eNorTk0uSi0BAAjRAoc="
func main() {
_, err := io.Copy(os.Stdout, decoder(strings.NewReader(nbody)))
if err != nil {
log.Fatalf("Error copying decoded value to stdout: %s",err)
}
}
// This could use any io.Reader as input, for example
// a request body in http requests
func decoder(r io.Reader) io.Reader {
// We simply set up a custom chain of Decoders
d, err := zlib.NewReader(
base64.NewDecoder(base64.StdEncoding, r))
// This should only occur if one of the Decoders can not reset
// its internal buffer. Hence, it validates a panic.
if err != nil {
panic(fmt.Sprintf("Error setting up decoder chain: %s", err))
}
// We return an io.Reader which can be used as any other
return d
}