1024
archivex/zipx/testdata/a/a.txt
vendored
Normal file
1024
archivex/zipx/testdata/a/a.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
archivex/zipx/testdata/b/b.txt
vendored
Normal file
1
archivex/zipx/testdata/b/b.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
b file content
|
||||
2
archivex/zipx/testdata/中国/你好.txt
vendored
Normal file
2
archivex/zipx/testdata/中国/你好.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Hello, China!
|
||||
你好,中国!
|
||||
163
archivex/zipx/zip.go
Normal file
163
archivex/zipx/zip.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package zipx
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.cloudyne.io/go/hiscaler-gox/filex"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type zipFile struct {
|
||||
header *zip.FileHeader
|
||||
data *os.File
|
||||
}
|
||||
|
||||
// Compress compresses files and saved, if compactDirectory is true, then will remove all directory path
|
||||
func Compress(filename string, files []string, method uint16, compactDirectory bool) error {
|
||||
zFile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer zFile.Close()
|
||||
zipWriter := zip.NewWriter(zFile)
|
||||
defer zipWriter.Close()
|
||||
|
||||
zipFiles := make([]zipFile, len(files))
|
||||
errGrp, ctx := errgroup.WithContext(context.Background())
|
||||
for i, file := range files {
|
||||
f := file
|
||||
j := i
|
||||
errGrp.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
zf, e := addFile(f, method, compactDirectory)
|
||||
if e != nil {
|
||||
ctx.Done()
|
||||
return e
|
||||
}
|
||||
zipFiles[j] = zf
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
err = errGrp.Wait()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range zipFiles {
|
||||
if zipFiles[i].data == nil {
|
||||
continue
|
||||
}
|
||||
err = func(i int) error {
|
||||
defer zipFiles[i].data.Close()
|
||||
if err != nil {
|
||||
return err // For close all opened files
|
||||
}
|
||||
writer, e := zipWriter.CreateHeader(zipFiles[i].header)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
_, e = io.Copy(writer, zipFiles[i].data)
|
||||
return e
|
||||
}(i)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func addFile(filename string, method uint16, compactDirectory bool) (zipFile zipFile, err error) {
|
||||
pendingAddFile, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer pendingAddFile.Close()
|
||||
|
||||
zipFile.data = pendingAddFile
|
||||
info, err := pendingAddFile.Stat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if compactDirectory {
|
||||
header.Name = filepath.Base(filename)
|
||||
} else {
|
||||
header.Name = filename
|
||||
}
|
||||
header.Method = method
|
||||
zipFile.header = header
|
||||
return
|
||||
}
|
||||
|
||||
// UnCompress unzip source file to destination directory
|
||||
func UnCompress(src, dst string) error {
|
||||
r, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer r.Close()
|
||||
|
||||
// Create destination directory if not exists
|
||||
if !filex.Exists(dst) {
|
||||
err = os.MkdirAll(dst, fs.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range r.File {
|
||||
path := filepath.Join(dst, file.Name)
|
||||
if file.FileInfo().IsDir() {
|
||||
if err = os.MkdirAll(path, file.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
if !filex.Exists(dir) {
|
||||
err = os.MkdirAll(dir, fs.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = writeFile(file, path); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func writeFile(file *zip.File, path string) error {
|
||||
fr, err := file.Open()
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
defer fr.Close()
|
||||
fw, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
_, err = io.Copy(fw, fr)
|
||||
return err
|
||||
}
|
||||
68
archivex/zipx/zip_test.go
Normal file
68
archivex/zipx/zip_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package zipx
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.cloudyne.io/go/hiscaler-gox/filex"
|
||||
)
|
||||
|
||||
var files []string
|
||||
|
||||
func init() {
|
||||
files = []string{
|
||||
"./zip.go",
|
||||
"./testdata/a/a.txt",
|
||||
"./testdata/b/b.txt",
|
||||
"./testdata/中国/你好.txt",
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompressCompactDirectory(t *testing.T) {
|
||||
err := Compress("./a.zip", files, zip.Deflate, true)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if !filex.Exists("./a.zip") {
|
||||
t.Error("zip file not exists")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompressUnCompactDirectory(t *testing.T) {
|
||||
err := Compress("./a.zip", files, zip.Deflate, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if !filex.Exists("./a.zip") {
|
||||
t.Error("zip file not exists")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompressError(t *testing.T) {
|
||||
notExistsFiles := make([]string, 0)
|
||||
for i := 0; i <= 100; i++ {
|
||||
notExistsFiles = append(notExistsFiles, fmt.Sprintf("%d-not-exists.file", i))
|
||||
}
|
||||
err := Compress("./a.zip", notExistsFiles, zip.Deflate, true)
|
||||
if err == nil {
|
||||
t.Error("err is nil")
|
||||
} else {
|
||||
t.Logf("err = %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnCompress(t *testing.T) {
|
||||
TestCompressUnCompactDirectory(t)
|
||||
err := UnCompress("./a.zip", "./a")
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else {
|
||||
for _, file := range files {
|
||||
checkFile := filepath.Join("./a", file)
|
||||
if !filex.Exists(checkFile) {
|
||||
t.Errorf("%s is not exists", checkFile)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user