Home > Net >  Golang - Zip a directory which includes empty subdirectory and files
Golang - Zip a directory which includes empty subdirectory and files

Time:12-26

I am trying to zip an existing directory that has some empty subdirectories as well.

Here is the folder structure.

parent/
├── child
│   └── child.txt
├── empty-folder
└── parent.txt

2 directories, 2 files

Here is the source code. It writes all the subdirectories which have files on that. But it skipped an empty subdirectory. Is there any way to add an empty subdirectory as well in the zip file?. Thanks in advance.

package main

import (
    "archive/zip"
    "fmt"
    "io"
    "os"
    "path/filepath"
)

// check for error and stop the execution
func checkForError(err error) {
    if err != nil {
        fmt.Println("Error - ", err)
        os.Exit(1)
    }
}

const (
    ZIP_FILE_NAME    = "example.zip"
    MAIN_FOLDER_NAME = "parent"
)

// Main function
func main() {

    var targetFilePaths []string

    // get filepaths in all folders
    err := filepath.Walk(MAIN_FOLDER_NAME, func(path string, info os.FileInfo, err error) error {
        if info.IsDir() {
            return nil
        }
        // add all the file paths to slice
        targetFilePaths = append(targetFilePaths, path)
        return nil
    })
    checkForError(err)

    // zip file logic starts here
    ZipFile, err := os.Create(ZIP_FILE_NAME)
    checkForError(err)
    defer ZipFile.Close()

    zipWriter := zip.NewWriter(ZipFile)
    defer zipWriter.Close()

    for _, targetFilePath := range targetFilePaths {

        file, err := os.Open(targetFilePath)
        checkForError(err)
        defer file.Close()

        // create path in zip
        w, err := zipWriter.Create(targetFilePath)
        checkForError(err)

        // write file to zip
        _, err = io.Copy(w, file)
        checkForError(err)

    }

}

CodePudding user response:

To write an empty directory you just need to call Create with the directory path with a trailing path separator.

package main

import (
    "archive/zip"
    "fmt"
    "io"
    "log"
    "os"
    "path/filepath"
)

const (
    ZIP_FILE_NAME    = "example.zip"
    MAIN_FOLDER_NAME = "parent"
)

type fileMeta struct {
    Path  string
    IsDir bool
}

func main() {
    var files []fileMeta
    err := filepath.Walk(MAIN_FOLDER_NAME, func(path string, info os.FileInfo, err error) error {
        files = append(files, fileMeta{Path: path, IsDir: info.IsDir()})
        return nil
    })
    if err != nil {
        log.Fatalln(err)
    }

    z, err := os.Create(ZIP_FILE_NAME)
    if err != nil {
        log.Fatalln(err)
    }
    defer z.Close()

    zw := zip.NewWriter(z)
    defer zw.Close()

    for _, f := range files {
        path := f.Path
        if f.IsDir {
            path = fmt.Sprintf("%s%c", path, os.PathSeparator)
        }

        w, err := zw.Create(path)
        if err != nil {
            log.Fatalln(err)
        }

        if !f.IsDir {
            file, err := os.Open(f.Path)
            if err != nil {
                log.Fatalln(err)
            }
            defer file.Close()

            if _, err = io.Copy(w, file); err != nil {
                log.Fatalln(err)
            }
        }
    }
}
  • Related