github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/compress/zip.go (about)

     1  package compress
     2  
     3  import (
     4  	"archive/zip"
     5  	"io"
     6  	"io/fs"
     7  	"os"
     8  	"path"
     9  	"path/filepath"
    10  	"strings"
    11  )
    12  
    13  //// Compress 压缩文件
    14  
    15  func Zip(zipPath string, paths []string) error {
    16  	// create zip file
    17  	if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil {
    18  		return err
    19  	}
    20  	archive, err := os.Create(zipPath)
    21  	if err != nil {
    22  		return err
    23  	}
    24  	defer func(archive *os.File) {
    25  		_ = archive.Close()
    26  	}(archive)
    27  
    28  	// new zip writer
    29  	zipWriter := zip.NewWriter(archive)
    30  	defer func(zipWriter *zip.Writer) {
    31  		_ = zipWriter.Close()
    32  	}(zipWriter)
    33  
    34  	// traverse the file or directory
    35  	for _, srcPath := range paths {
    36  		// remove the trailing path separator if path is a directory
    37  		srcPath = strings.TrimSuffix(srcPath, string(os.PathSeparator))
    38  
    39  		// visit all the files or directories in the tree
    40  		err = filepath.Walk(srcPath, func(path string, info fs.FileInfo, err error) error {
    41  			if err != nil {
    42  				return err
    43  			}
    44  
    45  			// create a local file header
    46  			header, err := zip.FileInfoHeader(info)
    47  			if err != nil {
    48  				return err
    49  			}
    50  
    51  			// set compression
    52  			header.Method = zip.Deflate
    53  
    54  			// set relative path of a file as the header name
    55  			header.Name, err = filepath.Rel(filepath.Dir(srcPath), path)
    56  			if err != nil {
    57  				return err
    58  			}
    59  			if info.IsDir() {
    60  				header.Name += string(os.PathSeparator)
    61  			}
    62  
    63  			// create writer for the file header and save content of the file
    64  			headerWriter, err := zipWriter.CreateHeader(header)
    65  			if err != nil {
    66  				return err
    67  			}
    68  			if info.IsDir() {
    69  				return nil
    70  			}
    71  			err = copyFile(path, headerWriter)
    72  			if err != nil {
    73  				return err
    74  			}
    75  			return err
    76  		})
    77  		if err != nil {
    78  			return err
    79  		}
    80  	}
    81  	return nil
    82  }
    83  
    84  func copyFile(fileSrcPath string, dstWriter io.Writer) error {
    85  	f, err := os.Open(fileSrcPath)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	defer func(f *os.File) {
    90  		_ = f.Close()
    91  	}(f)
    92  	_, err = io.Copy(dstWriter, f)
    93  	return err
    94  }
    95  
    96  // Unzip decompresses a zip file to specified directory.
    97  // Note that the destination directory don't need to specify the trailing path separator.
    98  func Unzip(zipPath, dstDir string) error {
    99  	// open zip file
   100  	reader, err := zip.OpenReader(zipPath)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	defer func(reader *zip.ReadCloser) {
   105  		_ = reader.Close()
   106  	}(reader)
   107  	for _, file := range reader.File {
   108  		if err := unzipFile(file, dstDir); err != nil {
   109  			return err
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  func unzipFile(file *zip.File, dstDir string) error {
   116  	// create the directory of file
   117  	filePath := path.Join(dstDir, file.Name)
   118  	if file.FileInfo().IsDir() {
   119  		if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
   120  			return err
   121  		}
   122  		return nil
   123  	}
   124  	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
   125  		return err
   126  	}
   127  
   128  	// open the file
   129  	rc, err := file.Open()
   130  	if err != nil {
   131  		return err
   132  	}
   133  	defer func(rc io.ReadCloser) {
   134  		_ = rc.Close()
   135  	}(rc)
   136  
   137  	// create the file
   138  	w, err := os.Create(filePath)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	defer func(w *os.File) {
   143  		_ = w.Close()
   144  	}(w)
   145  
   146  	// save the decompressed file content
   147  	_, err = io.Copy(w, rc)
   148  	return err
   149  }