morpheus
morpheus

Reputation: 20330

How to uncompress a file generated by the Go compress/gzip package using the command line?

I have a file that was generated using the Go compress/gzip package with code like

payload := bytes.NewBuffer(nil)
gw := gzip.NewWriter(payload)
tw := tar.NewWriter(gw)
...
tw.Close()
gw.Close()

How can I unzip this file from the command line on Mac? I tried gunzip but it fails

$ gunzip test.gz
gunzip: test.gz: not in gzip format

Also tried following without luck

$ tar -xvf test.gz
tar: Unrecognized archive format
tar: Error exit delayed from previous errors.

Upvotes: 0

Views: 491

Answers (1)

Ullaakut
Ullaakut

Reputation: 3734

Your issue is that you are never writing to your tar writer, in your example code. In order to produce a valid targz file with content, you need to keep in mind that:

  • Add at least one file needs to be in the tarball
  • Each file requires headers

You'll need to use tar.WriteHeader to create the header for each file, and you can then simply write the content of the files as bytes through a call to tar.Write.

You can then untar it using tar -xvf test.tgz like you mentioned in your previous example.

Here is a sample code that I quickly wrote on my machine for the sake of demonstration:

package main

import (
    "compress/gzip"
    "archive/tar"
    "os"
    "fmt"
    "time"
)

func main() {
    // Create targz file which will contain other files.
    file, err := os.Create("test.tgz")
    if err != nil {
        panic(err)
    }

    gw := gzip.NewWriter(file)
    defer gw.Close()

    tw := tar.NewWriter(gw)
    defer tw.Close()

    // Create file(s) in targz
    if err := addFile(tw, "myfile.test", "example content"); err != nil {
        panic(err)
    }
}

func addFile(tw *tar.Writer, fileName, content string) error {
    header := &tar.Header{
        Name:    fileName,
        Size:    int64(len(content)),
        Mode:    0655,
        ModTime: time.Now(),
    }

    err := tw.WriteHeader(header)
    if err != nil {
        return fmt.Errorf("could not write header for file %q: %w", fileName, err)
    }

    _, err = tw.Write([]byte(content))
    if err != nil {
        return fmt.Errorf("could not write content for file %q: %w", fileName, err)
    }

    return nil
}

And here is the result:

$> go run main.go

$> ls -la
total 5
drwxr-xr-x  12 ullaakut  staff   384 Feb 12 05:34 ./
drwxr-xr-x  29 ullaakut  staff   928 Jan 28 14:56 ../
-rw-r--r--@  1 ullaakut  staff  6148 Dec 25 13:01 .DS_Store
-rw-r--r--   1 ullaakut  staff   888 Feb 12 05:34 main.go
-rw-r--r--   1 ullaakut  staff   121 Feb 12 05:34 test.tgz

$> tar -zxvf test.tgz
x myfile.test

$> cat myfile.test
example content

As you can see, the archive is extracted and uncompressed just fine :)

Upvotes: 1

Related Questions