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
import (
"archive/zip"
"fmt"
"github.com/gogf/gf/encoding/gcompress"
"io"
"os"
"path/filepath"
"strings"
)
func main() {
err := gcompress.ZipPath(
`/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test`,
`/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test.zip`,
)
fmt.Println(err)
// 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() {
src := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test`
dst := `/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(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")
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(gfile.Exists(dstPath), true)
defer gfile.Remove(dstPath)
// unzip to another temporary dir.
tempDirPath := gfile.TempDir(gtime.TimestampNanoStr())
err = gfile.Mkdir(tempDirPath)
t.Assert(err, nil)
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, "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) {
srcPath := gdebug.TestDataPath("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")),
)
})
// multiple paths joined using char ','
// multiple directory paths joined using char ','.
gtest.C(t, func(t *gtest.T) {
srcPath := gdebug.TestDataPath("zip")
srcPath1 := gdebug.TestDataPath("zip", "path1")
srcPath2 := gdebug.TestDataPath("zip", "path2")
dstPath := gdebug.TestDataPath("zip", "zip.zip")
var (
srcPath = gdebug.TestDataPath("zip")
srcPath1 = gdebug.TestDataPath("zip", "path1")
srcPath2 = gdebug.TestDataPath("zip", "path2")
dstPath = gdebug.TestDataPath("zip", "zip.zip")
)
pwd := gfile.Pwd()
err := gfile.Chdir(srcPath)
defer gfile.Chdir(pwd)
@ -116,10 +180,11 @@ func Test_ZipPath(t *testing.T) {
func Test_ZipPathWriter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
srcPath := gdebug.TestDataPath("zip")
srcPath1 := gdebug.TestDataPath("zip", "path1")
srcPath2 := gdebug.TestDataPath("zip", "path2")
var (
srcPath = gdebug.TestDataPath("zip")
srcPath1 = gdebug.TestDataPath("zip", "path1")
srcPath2 = gdebug.TestDataPath("zip", "path2")
)
pwd := gfile.Pwd()
err := gfile.Chdir(srcPath)
defer gfile.Chdir(pwd)

View File

@ -10,16 +10,12 @@ import (
"archive/zip"
"bytes"
"github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/text/gstr"
"io"
"os"
"path/filepath"
"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.
@ -85,11 +81,13 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix
headerPrefix = prefix[0]
}
headerPrefix = strings.TrimRight(headerPrefix, "\\/")
if len(headerPrefix) > 0 && gfile.IsDir(path) {
headerPrefix += "/"
}
if headerPrefix == "" {
headerPrefix = gfile.Basename(path)
if gfile.IsDir(path) {
if len(headerPrefix) > 0 {
headerPrefix += "/"
} else {
headerPrefix = gfile.Basename(path)
}
}
headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
for _, file := range files {
@ -97,23 +95,15 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix
intlog.Printf(`exclude file path: %s`, file)
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 {
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
}
@ -203,14 +193,23 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
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.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := zw.CreateHeader(header)
if err != nil {
return err
@ -223,23 +222,12 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
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, `/`)

View File

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