Home > Enterprise >  Convert zipped []byte to unzip []byte golang code
Convert zipped []byte to unzip []byte golang code

Time:09-15

I have []byte of zip file. I have to unzip it without creating a new file, and get a []byte of that unzipped file. Please help me to do that.

I am making an API call and the response I get is the []byte in zipped format - I am trying to unzip it - and use it's content for creating a new zip file. So unzip - rezip.

Language: Golang

Code I've used:

func UnzipBytes(zippedBytes []byte) ([]byte, error) {

    reader := bytes.NewReader(zippedBytes)
    zipReader, err := zlib.NewReader(reader)
    if err != nil {
        return nil, err
    }
    defer zipReader.Close()
    p, err := ioutil.ReadAll(zipReader)
    if err != nil {
        return nil, err
    }
    return p, nil
}

I get an error saying "zlib: invalid header"

The code that was initially used to zip the []byte

buffer := new(bytes.Buffer)
zipWriter := zip.NewWriter(buffer)
zipFile, err := zipWriter.Create(file.name)
_, err = zipFile.Write(file.content)

Hex dump of the []byte - the zippedBytes

00059350  78 b4 5b 0d 2b 81 c2 87  35 76 1b 11 4a ec 07 d1  |x.[. ...5v..J...|
00059360  76 77 a2 e1 3b d9 12 e2  51 d4 c5 bd 4b 2f 09 da  |vw..;...Q...K/..|
00059370  f7 21 c7 26 73 1f 8e da  f0 ff a3 52 f6 e2 00 e6  |.!.&s......R....|

CodePudding user response:

You used zip.Writer to compress the data. You must close it by calling its Writer.Close() method. And you must use zip.Reader to read it, and use Reader.Open() with the same name you used when compressed it (file.name).

This is how it could look like:

func UnzipBytes(name string, zippedBytes []byte) ([]byte, error) {
    reader := bytes.NewReader(zippedBytes)
    zipReader, err := zip.NewReader(reader, int64(len(zippedBytes)))
    if err != nil {
        return nil, err
    }
    f, err := zipReader.Open(name)
    if err != nil {
        panic(err)
    }
    p, err := ioutil.ReadAll(f)
    if err != nil {
        return nil, err
    }
    return p, nil
}

Testing it:

filename := "test.txt"
filecontent := []byte("line1\nline2")

buffer := new(bytes.Buffer)
zipWriter := zip.NewWriter(buffer)
zipFile, err := zipWriter.Create(filename)
if err != nil {
    panic(err)
}
if _, err = zipFile.Write(filecontent); err != nil {
    panic(err)
}
if err = zipWriter.Close(); err != nil {
    panic(err)
}

decoded, err := UnzipBytes(filename, buffer.Bytes())
fmt.Println(err)
fmt.Println(string(decoded))

This will output (try it on the Go Playground):

<nil>
line1
line2

If you don't know the name when decompressing, you may see all files in the Reader.Files header field. You may choose to open the first file:

func UnzipBytes(zippedBytes []byte) ([]byte, error) {
    reader := bytes.NewReader(zippedBytes)
    zipReader, err := zip.NewReader(reader, int64(len(zippedBytes)))
    if err != nil {
        return nil, err
    }
    if len(zipReader.File) == 0 {
        return nil, nil // No file to open / extract
    }
    f, err := zipReader.File[0].Open()
    if err != nil {
        panic(err)
    }
    p, err := ioutil.ReadAll(f)
    if err != nil {
        return nil, err
    }
    return p, nil
}

This outputs the same. Try this one on the Go Playground.

  • Related