用golang解压缩gzip字符串

时间:2019-04-10 00:02:21

标签: go gzip

我有一个包含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))

4 个答案:

答案 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

}

Run on playground