fix issue in zip feature for package gcompress; improve package gres

This commit is contained in:
John 2020-05-01 00:18:45 +08:00
parent 3db83e1159
commit f7c2a51c9f
8 changed files with 324 additions and 64 deletions

View File

@ -1,15 +1,68 @@
package main package main
import ( import (
"archive/zip"
"fmt" "fmt"
"github.com/gogf/gf/encoding/gcompress" "github.com/gogf/gf/encoding/gcompress"
"io"
"os"
"path/filepath"
"strings"
) )
// srcFile could be a single file or a directory
func Zip(srcFile string, destZip string) error {
zipfile, err := os.Create(destZip)
if err != nil {
return err
}
defer zipfile.Close()
archive := zip.NewWriter(zipfile)
defer archive.Close()
filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = strings.TrimPrefix(path, filepath.Dir(srcFile)+"/")
// header.Name = path
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if !info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
}
return err
})
return err
}
func main() { func main() {
err := gcompress.ZipPath( src := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test`
`/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test`, dst := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test.zip`
`/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test.zip`, //src := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/README.MD`
) //dst := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/README.MD.zip`
fmt.Println(err) fmt.Println(gcompress.ZipPath(src, dst))
//fmt.Println(Zip(src, dst))
} }

View File

@ -24,25 +24,88 @@ func Test_ZipPath(t *testing.T) {
dstPath := gdebug.TestDataPath("zip", "zip.zip") dstPath := gdebug.TestDataPath("zip", "zip.zip")
t.Assert(gfile.Exists(dstPath), false) t.Assert(gfile.Exists(dstPath), false)
err := gcompress.ZipPath(srcPath, dstPath) t.Assert(gcompress.ZipPath(srcPath, dstPath), nil)
t.Assert(gfile.Exists(dstPath), true)
defer gfile.Remove(dstPath)
// unzip to temporary dir.
tempDirPath := gfile.TempDir(gtime.TimestampNanoStr())
t.Assert(gfile.Mkdir(tempDirPath), nil)
t.Assert(gcompress.UnZipFile(dstPath, tempDirPath), nil)
defer gfile.Remove(tempDirPath)
t.Assert(
gfile.GetContents(gfile.Join(tempDirPath, "1.txt")),
gfile.GetContents(srcPath),
)
})
// multiple files
gtest.C(t, func(t *gtest.T) {
var (
srcPath1 = gdebug.TestDataPath("zip", "path1", "1.txt")
srcPath2 = gdebug.TestDataPath("zip", "path2", "2.txt")
dstPath = gfile.TempDir(gtime.TimestampNanoStr(), "zip.zip")
)
if p := gfile.Dir(dstPath); !gfile.Exists(p) {
t.Assert(gfile.Mkdir(p), nil)
}
t.Assert(gfile.Exists(dstPath), false)
err := gcompress.ZipPath(srcPath1+","+srcPath2, dstPath)
t.Assert(err, nil) t.Assert(err, nil)
t.Assert(gfile.Exists(dstPath), true) t.Assert(gfile.Exists(dstPath), true)
defer gfile.Remove(dstPath) defer gfile.Remove(dstPath)
// unzip to another temporary dir.
tempDirPath := gfile.TempDir(gtime.TimestampNanoStr()) tempDirPath := gfile.TempDir(gtime.TimestampNanoStr())
err = gfile.Mkdir(tempDirPath) t.Assert(gfile.Mkdir(tempDirPath), nil)
t.Assert(err, nil)
err = gcompress.UnZipFile(dstPath, tempDirPath) err = gcompress.UnZipFile(dstPath, tempDirPath)
t.Assert(err, nil) t.Assert(err, nil)
defer gfile.Remove(tempDirPath) defer gfile.Remove(tempDirPath)
t.Assert( t.Assert(
gfile.GetContents(gfile.Join(tempDirPath, "1.txt")), gfile.GetContents(gfile.Join(tempDirPath, "1.txt")),
gfile.GetContents(gfile.Join(srcPath, "path1", "1.txt")), gfile.GetContents(srcPath1),
)
t.Assert(
gfile.GetContents(gfile.Join(tempDirPath, "2.txt")),
gfile.GetContents(srcPath2),
) )
}) })
// directory // one dir and one file.
gtest.C(t, func(t *gtest.T) {
var (
srcPath1 = gdebug.TestDataPath("zip", "path1")
srcPath2 = gdebug.TestDataPath("zip", "path2", "2.txt")
dstPath = gfile.TempDir(gtime.TimestampNanoStr(), "zip.zip")
)
if p := gfile.Dir(dstPath); !gfile.Exists(p) {
t.Assert(gfile.Mkdir(p), nil)
}
t.Assert(gfile.Exists(dstPath), false)
err := gcompress.ZipPath(srcPath1+","+srcPath2, dstPath)
t.Assert(err, nil)
t.Assert(gfile.Exists(dstPath), true)
defer gfile.Remove(dstPath)
// unzip to another temporary dir.
tempDirPath := gfile.TempDir(gtime.TimestampNanoStr())
t.Assert(gfile.Mkdir(tempDirPath), nil)
err = gcompress.UnZipFile(dstPath, tempDirPath)
t.Assert(err, nil)
defer gfile.Remove(tempDirPath)
t.Assert(
gfile.GetContents(gfile.Join(tempDirPath, "path1", "1.txt")),
gfile.GetContents(gfile.Join(srcPath1, "1.txt")),
)
t.Assert(
gfile.GetContents(gfile.Join(tempDirPath, "2.txt")),
gfile.GetContents(srcPath2),
)
})
// directory.
gtest.C(t, func(t *gtest.T) { gtest.C(t, func(t *gtest.T) {
srcPath := gdebug.TestDataPath("zip") srcPath := gdebug.TestDataPath("zip")
dstPath := gdebug.TestDataPath("zip", "zip.zip") dstPath := gdebug.TestDataPath("zip", "zip.zip")
@ -75,13 +138,14 @@ func Test_ZipPath(t *testing.T) {
gfile.GetContents(gfile.Join(srcPath, "path2", "2.txt")), gfile.GetContents(gfile.Join(srcPath, "path2", "2.txt")),
) )
}) })
// multiple paths joined using char ',' // multiple directory paths joined using char ','.
gtest.C(t, func(t *gtest.T) { gtest.C(t, func(t *gtest.T) {
srcPath := gdebug.TestDataPath("zip") var (
srcPath1 := gdebug.TestDataPath("zip", "path1") srcPath = gdebug.TestDataPath("zip")
srcPath2 := gdebug.TestDataPath("zip", "path2") srcPath1 = gdebug.TestDataPath("zip", "path1")
dstPath := gdebug.TestDataPath("zip", "zip.zip") srcPath2 = gdebug.TestDataPath("zip", "path2")
dstPath = gdebug.TestDataPath("zip", "zip.zip")
)
pwd := gfile.Pwd() pwd := gfile.Pwd()
err := gfile.Chdir(srcPath) err := gfile.Chdir(srcPath)
defer gfile.Chdir(pwd) defer gfile.Chdir(pwd)
@ -116,10 +180,11 @@ func Test_ZipPath(t *testing.T) {
func Test_ZipPathWriter(t *testing.T) { func Test_ZipPathWriter(t *testing.T) {
gtest.C(t, func(t *gtest.T) { gtest.C(t, func(t *gtest.T) {
srcPath := gdebug.TestDataPath("zip") var (
srcPath1 := gdebug.TestDataPath("zip", "path1") srcPath = gdebug.TestDataPath("zip")
srcPath2 := gdebug.TestDataPath("zip", "path2") srcPath1 = gdebug.TestDataPath("zip", "path1")
srcPath2 = gdebug.TestDataPath("zip", "path2")
)
pwd := gfile.Pwd() pwd := gfile.Pwd()
err := gfile.Chdir(srcPath) err := gfile.Chdir(srcPath)
defer gfile.Chdir(pwd) defer gfile.Chdir(pwd)

View File

@ -10,16 +10,12 @@ import (
"archive/zip" "archive/zip"
"bytes" "bytes"
"github.com/gogf/gf/internal/intlog" "github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/text/gstr"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/gogf/gf/internal/fileinfo"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/text/gstr"
) )
// ZipPath compresses <paths> to <dest> using zip compressing algorithm. // ZipPath compresses <paths> to <dest> using zip compressing algorithm.
@ -85,35 +81,29 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix
headerPrefix = prefix[0] headerPrefix = prefix[0]
} }
headerPrefix = strings.TrimRight(headerPrefix, "\\/") headerPrefix = strings.TrimRight(headerPrefix, "\\/")
if len(headerPrefix) > 0 && gfile.IsDir(path) { if gfile.IsDir(path) {
if len(headerPrefix) > 0 {
headerPrefix += "/" headerPrefix += "/"
} } else {
if headerPrefix == "" {
headerPrefix = gfile.Basename(path) headerPrefix = gfile.Basename(path)
} }
}
headerPrefix = strings.Replace(headerPrefix, "//", "/", -1) headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
for _, file := range files { for _, file := range files {
if exclude == file { if exclude == file {
intlog.Printf(`exclude file path: %s`, file) intlog.Printf(`exclude file path: %s`, file)
continue continue
} }
err := zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter) dir := gfile.Dir(file[len(path):])
if dir == "." {
dir = ""
}
err := zipFile(file, headerPrefix+dir, zipWriter)
if err != nil { if err != nil {
return err return err
} }
} }
// Add prefix to zip archive.
path = headerPrefix
for {
err := zipFileVirtual(fileinfo.New(gfile.Basename(path), 0, os.ModeDir, time.Now()), path, zipWriter)
if err != nil {
return err
}
if path == "/" || !strings.Contains(path, "/") {
break
}
path = gfile.Dir(path)
}
return nil return nil
} }
@ -203,14 +193,23 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
return nil return nil
} }
defer file.Close() defer file.Close()
info, err := file.Stat() info, err := file.Stat()
if err != nil { if err != nil {
return err return err
} }
header, err := createFileHeader(info, prefix) header, err := createFileHeader(info, prefix)
if err != nil { if err != nil {
return err return err
} }
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := zw.CreateHeader(header) writer, err := zw.CreateHeader(header)
if err != nil { if err != nil {
return err return err
@ -223,23 +222,12 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
return nil return nil
} }
func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error {
header, err := createFileHeader(info, "")
if err != nil {
return err
}
header.Name = path
if _, err := zw.CreateHeader(header); err != nil {
return err
}
return nil
}
func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) { func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {
header, err := zip.FileInfoHeader(info) header, err := zip.FileInfoHeader(info)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(prefix) > 0 { if len(prefix) > 0 {
prefix = strings.Replace(prefix, `\`, `/`, -1) prefix = strings.Replace(prefix, `\`, `/`, -1)
prefix = strings.TrimRight(prefix, `/`) prefix = strings.TrimRight(prefix, `/`)

View File

@ -11,9 +11,9 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/gogf/gf/encoding/gcompress"
"github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/encoding/gcompress"
"github.com/gogf/gf/os/gfile" "github.com/gogf/gf/os/gfile"
) )
@ -41,7 +41,7 @@ func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
if len(keyPrefix) > 0 && keyPrefix[0] != "" { if len(keyPrefix) > 0 && keyPrefix[0] != "" {
headerPrefix = keyPrefix[0] headerPrefix = keyPrefix[0]
} }
err := gcompress.ZipPathWriter(srcPaths, buffer, headerPrefix) err := zipPathWriter(srcPaths, buffer, headerPrefix)
if err != nil { if err != nil {
return nil, err return nil, err
} }

153
os/gres/gres_func_zip.go Normal file
View File

@ -0,0 +1,153 @@
// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gres
import (
"archive/zip"
"github.com/gogf/gf/internal/fileinfo"
"github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/os/gfile"
"io"
"os"
"strings"
"time"
)
// ZipPathWriter compresses <paths> to <writer> using zip compressing algorithm.
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
//
// Note that the parameter <paths> can be either a directory or a file, which
// supports multiple paths join with ','.
func zipPathWriter(paths string, writer io.Writer, prefix ...string) error {
zipWriter := zip.NewWriter(writer)
defer zipWriter.Close()
for _, path := range strings.Split(paths, ",") {
path = strings.TrimSpace(path)
if err := doZipPathWriter(path, "", zipWriter, prefix...); err != nil {
return err
}
}
return nil
}
// doZipPathWriter compresses the file of given <path> and writes the content to <zipWriter>.
// The parameter <exclude> specifies the exclusive file path that is not compressed to <zipWriter>,
// commonly the destination zip file path.
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix ...string) error {
var err error
var files []string
path, err = gfile.Search(path)
if err != nil {
return err
}
if gfile.IsDir(path) {
files, err = gfile.ScanDir(path, "*", true)
if err != nil {
return err
}
} else {
files = []string{path}
}
headerPrefix := ""
if len(prefix) > 0 && prefix[0] != "" {
headerPrefix = prefix[0]
}
headerPrefix = strings.TrimRight(headerPrefix, "\\/")
if len(headerPrefix) > 0 && gfile.IsDir(path) {
headerPrefix += "/"
}
if headerPrefix == "" {
headerPrefix = gfile.Basename(path)
}
headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
for _, file := range files {
if exclude == file {
intlog.Printf(`exclude file path: %s`, file)
continue
}
err := zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter)
if err != nil {
return err
}
}
// Add all directories to zip archive.
if headerPrefix != "" {
var name string
path = headerPrefix
for {
name = gfile.Basename(path)
err := zipFileVirtual(
fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), path, zipWriter,
)
if err != nil {
return err
}
if path == "/" || !strings.Contains(path, "/") {
break
}
path = gfile.Dir(path)
}
}
return nil
}
// zipFile compresses the file of given <path> and writes the content to <zw>.
// The parameter <prefix> indicates the path prefix for zip file.
func zipFile(path string, prefix string, zw *zip.Writer) error {
file, err := os.Open(path)
if err != nil {
return nil
}
defer file.Close()
info, err := file.Stat()
if err != nil {
return err
}
header, err := createFileHeader(info, prefix)
if err != nil {
return err
}
if !info.IsDir() {
header.Method = zip.Deflate
}
writer, err := zw.CreateHeader(header)
if err != nil {
return err
}
if !info.IsDir() {
if _, err = io.Copy(writer, file); err != nil {
return err
}
}
return nil
}
func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error {
header, err := createFileHeader(info, "")
if err != nil {
return err
}
header.Name = path
if _, err := zw.CreateHeader(header); err != nil {
return err
}
return nil
}
func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {
header, err := zip.FileInfoHeader(info)
if err != nil {
return nil, err
}
if len(prefix) > 0 {
prefix = strings.Replace(prefix, `\`, `/`, -1)
prefix = strings.TrimRight(prefix, `/`)
header.Name = prefix + `/` + header.Name
}
return header, nil
}

View File

@ -35,9 +35,10 @@ func Test_Pack(t *testing.T) {
t.Assert(err, nil) t.Assert(err, nil)
r := gres.New() r := gres.New()
err = r.Add(string(data)) err = r.Add(string(data))
t.Assert(err, nil) t.Assert(err, nil)
t.Assert(r.Contains("files"), true) t.Assert(r.Contains("files/"), true)
}) })
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long