godoos/godo/files/unzip.go
2024-08-01 17:27:02 +08:00

219 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package files
import (
"compress/bzip2"
"compress/gzip"
"fmt"
"godo/libs"
"io"
"os"
"path/filepath"
"strings"
"archive/tar"
"archive/zip"
)
// Decompress 解压文件到指定目录,支持多种压缩格式
func Decompress(compressedFilePath, destPath string) (string, error) {
ext := filepath.Ext(compressedFilePath)
switch ext {
case ".zip":
return Unzip(compressedFilePath, destPath)
case ".tar":
tarFile, err := os.Open(compressedFilePath)
if err != nil {
return "", err
}
defer tarFile.Close()
return Untar(tarFile, destPath)
case ".gz":
return Untargz(compressedFilePath, destPath)
case ".bz2":
return Untarbz2(compressedFilePath, destPath)
default:
return "", fmt.Errorf("unsupported compression format: %s", ext)
}
}
// Untar 解压.tar文件到指定目录
func Untar(reader io.Reader, destPath string) (string, error) {
var topLevelDirName string
tarReader := tar.NewReader(reader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return "", err
}
// Determine the top-level directory name
if header.Typeflag == tar.TypeDir && topLevelDirName == "" {
topLevelDirName = header.Name
} else {
topLevelDirName = destPath
}
target := filepath.Join(destPath, header.Name)
if header.Typeflag == tar.TypeDir {
if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil {
return "", err
}
continue
}
if err := os.MkdirAll(filepath.Dir(target), os.ModePerm); err != nil {
return "", err
}
outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode))
if err != nil {
return "", err
}
defer outFile.Close()
if _, err := io.Copy(outFile, tarReader); err != nil {
return "", err
}
}
// Return the full path of the top-level directory
topLevelDestPath := filepath.Join(destPath, topLevelDirName)
return topLevelDestPath, nil
}
// Untargz 解压.tar.gz文件到指定目录
func Untargz(targzFilePath, destPath string) (string, error) {
gzFile, err := os.Open(targzFilePath)
if err != nil {
return "", err
}
defer gzFile.Close()
gzReader, err := gzip.NewReader(gzFile)
if err != nil {
return "", err
}
defer gzReader.Close()
return Untar(gzReader, destPath)
}
// Untarbz2 解压.tar.bz2文件到指定目录
func Untarbz2(tarbz2FilePath, destPath string) (string, error) {
bz2File, err := os.Open(tarbz2FilePath)
if err != nil {
return "", err
}
defer bz2File.Close()
bz2Reader := bzip2.NewReader(bz2File)
return Untar(bz2Reader, destPath)
}
// DecompressZip 解压zip文件到指定目录
func Unzip(zipFilePath, destPath string) (string, error) {
r, err := zip.OpenReader(zipFilePath)
if err != nil {
return "", err
}
defer r.Close()
// 初始化顶层目录名称为空
var topLevelDirName string
var topLevelDestPath string
// 遍历ZIP文件中的每个条目
for _, f := range r.File {
// 如果是目录且不是根目录,则更新顶层目录名称
if f.FileInfo().IsDir() && f.Name != "" {
// 去掉末尾的斜杠
cleanedName := strings.TrimSuffix(f.Name, string(os.PathSeparator))
if topLevelDirName == "" || cleanedName < topLevelDirName {
topLevelDirName = cleanedName
}
}
}
// 检查是否找到了顶层目录
if topLevelDirName == "" {
topLevelDestPath = destPath
} else {
// 完整的顶层目录路径
topLevelDestPath = filepath.Join(destPath, topLevelDirName)
}
// 再次遍历ZIP文件中的每个条目这次进行解压操作
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return "", err
}
defer rc.Close()
// 调整路径以确保所有文件都在顶层目录内
//path := filepath.Join(topLevelDestPath, strings.TrimPrefix(f.Name, topLevelDirName+string(os.PathSeparator)))
path := filepath.Join(topLevelDestPath, strings.TrimPrefix(f.Name, topLevelDirName))
// 确保父目录存在
if !libs.PathExists(filepath.Dir(path)) {
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return "", err
}
}
if f.FileInfo().IsDir() {
// 创建目录
if !libs.PathExists(path) {
if err := os.Mkdir(path, f.Mode()); err != nil {
return "", err
}
}
} else {
// 创建并写入文件
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return "", err
}
defer outFile.Close()
if _, err := io.Copy(outFile, rc); err != nil {
return "", err
}
}
}
// 返回完整的顶层目录路径
return topLevelDestPath, nil
}
// IsSupportedCompressionFormat 判断文件后缀是否为支持的压缩格式
func IsSupportedCompressionFormat(filename string) bool {
supportedFormats := map[string]bool{
".zip": true,
".tar": true,
".gz": true,
".bz2": true,
}
for format := range supportedFormats {
if strings.HasSuffix(strings.ToLower(filename), format) {
return true
}
}
return false
}
// HandlerFile 根据文件后缀判断是否支持解压,支持则解压,否则移动文件
func HandlerFile(filePath string, destDir string) (string, error) {
// log.Printf("HandlerFile: %s", filePath)
// log.Printf("destDir: %s", destDir)
if IsSupportedCompressionFormat(filePath) {
return Decompress(filePath, destDir)
} else {
return "", fmt.Errorf("unsupported compression format: %s", filePath)
}
}