Trusted answers to developer questions

How to uncompress a file in Golang

To protect and secure files, files are zipped and compressed. However, there is a need to unzip files for their usage. The .ZIP extension is the standard file extension for compressed files. However, there are other file extensions used for zipped files which include the following formats:

  • .JAR
  • .WAR
  • .DOCX
  • .ODS
  • .ODP

Go’s standard library has a package called "archive/zip". This package is used for compressing and decompressing files.

Packages in Go

Before delving into unzipping a file, there are core components that help us achieve this. Go’s standard library provides all the packages needed without the need to import an external library. We will be using five packages to achieve this. The packages are:

  1. The os package
  2. The io package
  3. The archive/zip package
  4. The path/filepath package
  5. The fmt package

The zip.OpenReader function

To unzip a file, the first thing to be done is to open the file. The zip.OpenReader handles this for us. So how does this function work?

The OpenReader function takes care of opening the zip file specified by it’s name and returns *ReadCloser and an error.

// The zip.OpenReader function
func OpenReader(name string) (*ReadCloser, error)
//The zip.Reader type
type Reader struct{
File []*File
Comment string
}

The reader

  • After the zip file is opened, it returns *ReadCloser which is an instance of zip.Reader. zip.Reader is a struct that has the field File of type []*zip.File and field Comment of type string.

  • A head start in the unzipping process is to name the destination folder to save the file to be unzipped. The file destinationFolder is declared as "unzipFolder".

package main
import (
"fmt"
"archive/zip"
"io"
"os"
"path/filepath"
)
func main() {
fileDestinationFolder := "unzipFolder"
//The first thing is to open the zipped file.
openedFile, err := zip.OpenReader("unzip/archive.zip")
if err != nil{
panic(err)
}
// postpone the closing of the file.
defer openedFile.Close()
}
  • The zipped file is opened with the zip.OpenReader function which takes in a parameter of the link to the folder where the zipped file folder is located. This returns an error and the instance of zip.Reader. In the code above, it is named openedFile. This is a slice of type File.
package main
import (
"fmt"
"archive/zip"
"io"
"os"
"path/filepath"
)
func main() {
for _, file := range openedFile.File{
filePath := filepath.Join(destinationFolder,file.Name)
fmt.Println("unzipping file", filePath)
// if the file is an empty directory, create a directory
if file.FileInfo().IsDir(){
// create the directory
os.MkdirAll(filePath,os.ModePerm)
continue
}
}
  • The openFile, which is a slice of type File, is looped through using the range method to get an individual file.

  • Using the filepath.Join() method, the destinationfolder and the file.Name are joined into a single path named filePath. This is where the unzipping process starts.

  • After this is done, the next step is to create a directory. This is achieved using the os.MkdirAll() method, if the file is in an empty directory.

if err := os.MkdirAll(filepath.Dir(filePath),os.ModePerm); err != nil{
panic(err)
}else {
destinationFile, err := os.OpenFile(filePath,os.O_CREATE|os.O_WRONLY|os.O_TRUNC,file.Mode())
if err != nil{
panic(err)
}
//Opening the file and copy it's contents
fileInArchive, err := file.Open()
if err != nil{
}
if _, err := io.Copy(destinationFile,fileInArchive); err != nil{
panic(err)
}
destinationFile.Close()
fileInArchive.Close()
}
}
}
  • The next condition checks if the file is within a directory. If these two conditions fail, then it opens the filePath using the os.Openfile() method.

  • Theos.O_CREATE creates a file if the file does not exist in the destination folder.

  • Theos.O_WRONLY opens the file in a write-only mode and os.O_TRUNC truncates the file when opened. Any of these could happen since it is executed by an OR operator.

  • This operation returns an error and thedestinationFile of type *file. The error is handled.

  • The final step is to open the contents of the file saved as fileInAchived. This is copied into thedestinationFile using the io package.

GOROOT=/usr/local/go #gosetup
GOPATH=/Users/decagon/go #gosetup
/usr/local/go/bin/go build -o /private/var/folders/8w/g4zndjnj2yl3p12p3ht_hryc0000gn/T/GoLand/___go_build_espresso_unzip espresso/unzip #gosetup
/private/var/folders/8w/g4zndjnj2yl3p12p3ht_hryc0000gn/T/GoLand/___go_build_espresso_unzip
open zip archive
unzipping file unzipFolder/csv/test.csv
Process finished with the exit code 0

Conclusion

Uncompressing the "unzip/archive.zip" file requires us to create a destinationFolder. The zipped file was opened with the openReader function. The openReader function returns an instance of zip.Reader and an error. The zip.Reader is a struct that contains a field File of type []*zip.File and a Comment of type String. The derived file is a slice. To get the individual file, we had to loop it and join the file name with the destinationFolder. We checked if the file was within an empty directory. A directory was created if it failed the conditions. The filePath was opened using the os.Openfile() method. The final step was to open the contents of the file saved as fileInAchived before copying it into thedestinationFile using the io.Copymethod.

RELATED TAGS

golang
packages

CONTRIBUTOR

Emmanuel Gbaragbo
Copyright ©2024 Educative, Inc. All rights reserved
Did you find this helpful?