In this tutorial series #9, we will learn how to decompress the .tar.gz file extension using Golang programming language with step by step guide.
#MaharlikansCode
#DecompressTarGZInGolang
#Golang
#GZIP
#LifeAsSoftwareDeveloper
#Maharlikans
#FilipinoSoftwareDeveloper
If you go with extra mile for buying me a cup of coffee, I appreciate it guys: https://ko-fi.com/maharlikanscode
Source Codes:
cmd/dcdir.go:
package cmd
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/fatih/color"
"github.com/itrepablik/itrlog"
"github.com/itrepablik/kopy"
"github.com/spf13/cobra"
)
// dcdirCmd represents the dcdir command
var dcdirCmd = &cobra.Command{
Use: "dcdir",
Short: "Decompress any single tar.gz file",
Long: `The dcdir command decompresses the specified directory or a folder including the sub-folders
and its contents as well. Only the .tar.gz compressed files will be extracted by the 'dcdir'
command in connection with the 'comdir' command that compresses the entire folder or directory.
Example of a valid directory path in Windows:
"C:\source_folder\filename.tar.gz"
Or using the network directories, example:
"\\hostname_or_ip\source_folder\filename.tar.gz"
Example of a valid directory path in Linux:
"/home/user/source_folder_to_compress/foldername.tar.gz".`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
// To make directory path separator a universal, in Linux "/" and in Windows "\" to auto change
// depends on the user's OS using the filepath.FromSlash organic Go's library.
src := filepath.FromSlash(args[0])
msg := `Start decompressing:`
color.Blue(msg + " " + src)
itrlog.Infow(msg, "src", src, "log_time", time.Now().Format(logDTFormat))
r, err := os.Open(src)
if err != nil {
itrlog.Errorw("error", "err", err, "log_time", time.Now().Format(logDTFormat))
fmt.Println("error")
return
}
if err := kopy.ExtractTarGz(r, src, dcdirLog); err != nil {
color.Red(err.Error())
itrlog.Errorw("error", "err", err, "log_time", time.Now().Format(logDTFormat))
return
}
msg = `Done decompressing:`
color.Green(msg + " " + src)
itrlog.Infow(msg, "src", src, "log_time", time.Now().Format(logDTFormat))
},
}
func init() {
rootCmd.AddCommand(dcdirCmd)
}
kopy.ExtractTarGz:
// ExtractTarGz extracts the tar.gz compressed file.
func ExtractTarGz(gzipStream io.Reader, src string, isLogCopiedFile bool) error {
uncompressedStream, err := gzip.NewReader(gzipStream)
if err != nil {
return err
}
tarReader := tar.NewReader(uncompressedStream)
fnExtract, fnExtractRoot, fnExtractCounter := "", "", 0
if b := strings.Contains(src, ComFileFormat); b {
fnExtract = strings.Replace(src, ComFileFormat, "", -1)
}
os.MkdirAll(fnExtract, os.ModePerm) // Create a new dst dir first
for true {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch header.Typeflag {
case tar.TypeDir:
fnExtractCounter++
if fnExtractCounter == 1 {
fnExtractRoot = filepath.FromSlash(header.Name) // Gets the root dir only e.g C:\a
}
folderPath := filepath.FromSlash(header.Name) //full dir path
extractFileTo := ""
// Replace the original folder root directory of the compressed folder to a new dst location.
if b := strings.Contains(folderPath, fnExtractRoot); b {
extractFileTo = strings.Replace(folderPath, fnExtractRoot, fnExtract, -1)
}
if err := os.MkdirAll(filepath.FromSlash(extractFileTo), os.ModePerm); err != nil {
return err
}
case tar.TypeReg:
folderPath := filepath.FromSlash(header.Name) //full file path
extractFileTo := ""
// Replace the original file path of each files from the compressed folder to a new dst location.
if b := strings.Contains(folderPath, fnExtractRoot); b {
extractFileTo = strings.Replace(folderPath, fnExtractRoot, fnExtract, -1)
}
outFile, err := os.Create(extractFileTo)
if err != nil {
return err
}
if _, err := io.Copy(outFile, tarReader); err != nil {
return err
}
// Only log when it's true
if isLogCopiedFile {
color.Magenta("extracting to: " + extractFileTo)
itrlog.Infow("extracting to: ", "dst", extractFileTo, "log_time", time.Now().Format(logDateTimeFormat))
}
defer outFile.Close()
default:
color.Red("unknown type: " + filepath.FromSlash(header.Name))
itrlog.Errorw("unknown type", "file_type", filepath.FromSlash(header.Name), "log_time", time.Now().Format(logDateTimeFormat))
}
}
return err
}