Trying to zip files without creating folder inside archive

Hello,

Really new with Go, trying to create a function that will grab a list of files and zip them up. Googled for a while today, i can easily archive files, but it also creates a folder inside the archive (which, for stupid reasons i don’t want to get into, won’t work). I basically need to take all the files in a directory, zip them with no folder structure, and that’s it. Here is kinda what i’m working with:

package main

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

func zipit(source, target string) error {
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	info, err := os.Stat(source)
	if err != nil {
		return nil
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		if baseDir != "" {
			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})

	return err
}

func main() {
	zipit("output/","ABG_Gather_Data.zip")
}

To do what you want, just strip the folder part from the beginning of all names.

func zipit(source, target string) error {
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	base := filepath.Base(source)

	err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			if source == path {
				return nil
			}
			path += "/"
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name = path[len(base)+1:]
		header.Method = zip.Deflate

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})
	if err != nil {
		return err
	}
	if err = archive.Flush(); err != nil {
		return err
	}
	return nil
}

Notice how I improved error handling: you didn’t catch the error from filepath.Walk and “defer Close()” also makes the error (which might happen when you actually write the buffered file to disk) disappear. To fix that, I just used Flush().

Finally, please decorate your errors. Instead of returning err, return fmt.Errorf("could not <write what you are trying to do>: %v", err) (for example, ‘create zip header’, ‘open file to include in archive’, ‘copy file into archive’).

Personal note: I hate zip files that don’t create a folder.

I will try this out in a bit…but yeah man, me too. The requirements gathering stated that the consumption of this zip couldn’t handle a folder…like what?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.