diff --git a/docs/fileutil.md b/docs/fileutil.md index 89ee54f..3e04b44 100644 --- a/docs/fileutil.md +++ b/docs/fileutil.md @@ -37,6 +37,7 @@ import ( - [ReadFileByLine](#ReadFileByLine) - [Zip](#Zip) - [UnZip](#UnZip) +- [ZipAppendEntry](#ZipAppendEntry) - [CurrentPath](#CurrentPath) - [IsZipFile](#IsZipFile) - [FileSize](#FileSize) @@ -478,6 +479,34 @@ func main() { } ``` +### ZipAppendEntry + +

Append a single file or directory by fpath to an existing zip file.

+ +Signature: + +```go +func ZipAppendEntry(fpath string, destPath string) error +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/fileutil" +) + +func main() { + err := fileutil.ZipAppendEntry("./test.txt", "./test.zip") + if err != nil { + fmt.Println(err) + } +} +``` + ### CurrentPath

return current absolute path.

diff --git a/docs/fileutil_zh-CN.md b/docs/fileutil_zh-CN.md index 3783032..c3340f7 100644 --- a/docs/fileutil_zh-CN.md +++ b/docs/fileutil_zh-CN.md @@ -30,13 +30,14 @@ import ( - [MiMeType](#MiMeType) - [IsExist](#IsExist) - [IsLink](#IsLink) -- [IsDir](#IsDir) +- [IsDir](#IsDir)画 - [ListFileNames](#ListFileNames) - [RemoveFile](#RemoveFile) - [ReadFileToString](#ReadFileToString) - [ReadFileByLine](#ReadFileByLine) - [Zip](#Zip) - [UnZip](#UnZip) +- [ZipAppendEntry](#ZipAppendEntry) - [CurrentPath](#CurrentPath) - [IsZipFile](#IsZipFile) - [FileSize](#FileSize) @@ -478,6 +479,34 @@ func main() { } ``` +### ZipAppendEntry + +

通过将单个文件或目录追加到现有的zip文件

+ +函数签名: + +```go +func ZipAppendEntry(fpath string, destPath string) error +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/fileutil" +) + +func main() { + err := fileutil.ZipAppendEntry("./test.txt", "./test.zip") + if err != nil { + fmt.Println(err) + } +} +``` + ### CurrentPath

返回当前位置的绝对路径。

diff --git a/fileutil/file.go b/fileutil/file.go index 185af9b..349012a 100644 --- a/fileutil/file.go +++ b/fileutil/file.go @@ -178,44 +178,7 @@ func Zip(fpath string, destPath string) error { archive := zip.NewWriter(zipFile) defer archive.Close() - filepath.Walk(fpath, 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(fpath)+"/") - - 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) - if err != nil { - return err - } - } - return nil - }) - - return nil + return addFileToArchive(fpath, archive) } // UnZip unzip the file and save it to destPath @@ -260,6 +223,99 @@ func UnZip(zipFile string, destPath string) error { return nil } +// ZipAppendEntry append a single file or directory by fpath to an existing zip file. +// Play: https://go.dev/play/p/cxvaT8TRNQp +func ZipAppendEntry(fpath string, destPath string) error { + tempFile, err := os.CreateTemp("", "temp.zip") + if err != nil { + return err + } + defer os.Remove(tempFile.Name()) + + zipReader, err := zip.OpenReader(destPath) + if err != nil { + return err + } + + archive := zip.NewWriter(tempFile) + + for _, zipItem := range zipReader.File { + zipItemReader, err := zipItem.Open() + if err != nil { + return err + } + header, err := zip.FileInfoHeader(zipItem.FileInfo()) + if err != nil { + return err + } + header.Name = zipItem.Name + targetItem, err := archive.CreateHeader(header) + if err != nil { + return err + } + _, err = io.Copy(targetItem, zipItemReader) + if err != nil { + return err + } + } + + err = addFileToArchive(fpath, archive) + + if err != nil { + return err + } + + err = zipReader.Close() + if err != nil { + return err + } + err = archive.Close() + if err != nil { + return err + } + err = tempFile.Close() + if err != nil { + return err + } + + return CopyFile(tempFile.Name(), destPath) +} + +func addFileToArchive(fpath string, archive *zip.Writer) error { + err := filepath.Walk(fpath, 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(fpath)+"/") + + if info.IsDir() { + header.Name += "/" + } else { + header.Method = zip.Deflate + writer, err := archive.CreateHeader(header) + if err != nil { + return err + } + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + if _, err := io.Copy(writer, file); err != nil { + return err + } + } + return nil + }) + return err +} + func safeFilepathJoin(path1, path2 string) (string, error) { relPath, err := filepath.Rel(".", path2) if err != nil || strings.HasPrefix(relPath, "..") { diff --git a/fileutil/file_test.go b/fileutil/file_test.go index 105bf7b..f9f05b6 100644 --- a/fileutil/file_test.go +++ b/fileutil/file_test.go @@ -182,6 +182,44 @@ func TestZipAndUnZip(t *testing.T) { os.RemoveAll(unZipPath) } +func TestZipAppendEntry(t *testing.T) { + assert := internal.NewAssert(t, "TestZipAppendEntry") + + zipFile := "./text.zip" + err := CopyFile("./testdata/file.go.zip", zipFile) + assert.IsNil(err) + + srcFile := "./text.txt" + CreateFile(srcFile) + + file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm) + + _, err = file.WriteString("hello\nworld") + if err != nil { + t.Fail() + } + file.Close() + + err = ZipAppendEntry(srcFile, zipFile) + assert.IsNil(err) + + err = ZipAppendEntry("./testdata", zipFile) + assert.IsNil(err) + + unZipPath := "./unzip" + err = UnZip(zipFile, unZipPath) + assert.IsNil(err) + + assert.Equal(true, IsExist("./unzip/text.txt")) + assert.Equal(true, IsExist("./unzip/file.go")) + assert.Equal(true, IsExist("./unzip/testdata/file.go.zip")) + assert.Equal(true, IsExist("./unzip/testdata/test.txt")) + + os.Remove(srcFile) + os.Remove(zipFile) + os.RemoveAll(unZipPath) +} + func TestFileMode(t *testing.T) { assert := internal.NewAssert(t, "TestFileMode")