I have a program in which I need to copy the folder contents (from folder1
) to a new folder (folder2
) in the same dir level (path). Since I cannot give the same name I use tmpFolder name (for folder2
). When I finish to do all the logic I need zip the copied folder and I give the zip the name folder1.zip
The problem is that when I extract the folder1.zip
I see folder2
.
I want it to be folder1
after the zip.
Is there some trick I can use to do it?
In addition, I know that I can copy to folder2 in different level (path) but I want to avoid it if possible since the copy can be very expensive when working on big folder contents.
I use this code to zip the folder:
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
}
Names of files and directories in zip archives come from the zip.FileHeader.
Your code already initializes the header from the os.FileInfo. This is important as it populates metadata such as timestamps and uncompressed size.
Furthermore, your code seems to be doing the following:
If invoked with:
Zipit("/path/to/folder2/", "/path/to/folder1.zip")
Before traversing the directory tree, it computes the base directory:
baseDir = filepath.Base(source)
// baseDir is "folder2"
Then for each file, the path inside the archive is set to:
header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
This turns a filename such as /path/to/folder2/otherdir/myfile
into folder2/otherdir/myfile
.
If you want to change the directory name stored inside the archive, you just need to change baseDir
to the desired name.
I would recommend the following solution:
Change the function signature to:
func Zipit(source, target, newBaseName string) error {
Change the basedir to:
if newBaseName != "" {
baseDir = newBaseName
else if info.IsDir() {
baseDir = filepath.Base(source)
}
Then call your function with:
Zipit("/path/to/folder2/", "/path/to/folder1.zip", "folder1")
This should result in an archive that extracts into folder1/
.