Go 解压/压缩
🏠 回到主页
Golang 解压/压缩 zip 文件
解压zip文件到指定目录,包含顶层文件夹
package zip
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
)
type ZipHandler struct {
}
func NewZipHandler() *ZipHandler {
return &ZipHandler{}
}
func (z *ZipHandler) UnZip(src, dst string) error {
archive, err := zip.OpenReader(src)
if err != nil {
return err
}
defer func(archive *zip.ReadCloser) {
err := archive.Close()
if err != nil {
return
}
}(archive)
for _, item := range archive.File {
filePath := filepath.Join(dst, item.Name)
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
if item.FileInfo().IsDir() {
err := os.MkdirAll(filePath, os.ModePerm)
if err != nil {
return err
}
continue
}
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, item.Mode())
if err != nil {
return err
}
fileInArchive, err := item.Open()
if err != nil {
return err
}
if _, err := io.Copy(file, fileInArchive); err != nil {
return err
}
}
return nil
}
解压zip文件到指定目录,不包含顶层文件夹,只是将文件解压到指定目录
这种适合压缩文件带了顶层文件夹,但是解压后不想要顶层文件夹的情况
package zip
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
)
type ZipHandler struct {
}
func NewZipHandler() *ZipHandler {
return &ZipHandler{}
}
func (z *ZipHandler) UnZipTo(src, dst string) error {
archive, err := zip.OpenReader(src)
if err != nil {
return err
}
defer func(archive *zip.ReadCloser) {
err := archive.Close()
if err != nil {
return
}
}(archive)
for _, item := range archive.File {
splitPath := strings.Split(item.Name, string(os.PathSeparator))
targetPath := strings.Join(splitPath[1:], string(os.PathSeparator))
filePath := filepath.Join(dst, targetPath)
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
if item.FileInfo().IsDir() {
err := os.MkdirAll(filePath, os.ModePerm)
if err != nil {
return err
}
continue
}
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, item.Mode())
if err != nil {
return err
}
fileInArchive, err := item.Open()
if err != nil {
return err
}
if _, err := io.Copy(file, fileInArchive); err != nil {
return err
}
}
return nil
}
压缩zip文件
Golang 中可以使用 archive/zip 包来进行文件的压缩和解压缩操作。以下是一个简单的示例程序,演示如何将一个文件夹压缩为 zip 文件:
package main
import (
"archive/zip"
"io"
"os"
"path/filepath"
)
func main() {
// 创建一个新的 zip 文件
zipfile, err := os.Create("test.zip")
if err != nil {
panic(err)
}
defer zipfile.Close()
// 创建一个 zip.Writer
zipWriter := zip.NewWriter(zipfile)
// 遍历要压缩的文件夹
dir := "./test"
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
// 如果是文件夹或者无法读取文件信息,则忽略
if info.IsDir() || err != nil {
return nil
}
// 打开文件
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
// 创建一个新的文件
zipFile, err := zipWriter.Create(path)
if err != nil {
return err
}
// 将文件内容写入到 zip 文件中
_, err = io.Copy(zipFile, file)
if err != nil {
return err
}
return nil
})
// 关闭 zip.Writer
err = zipWriter.Close()
if err != nil {
panic(err)
}
}
Golang 解压/压缩 tar.gz 文件
解压tar.gz文件到指定目录,包含顶层文件夹
package tar
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"path"
"path/filepath"
"strings"
)
type TGZHandler struct {
}
func NewTGZHandler() *TGZHandler {
return &TGZHandler{}
}
func (z *TGZHandler) UNTarGZ(src, dst string) error {
archive, err := os.Open(src)
if err != nil {
return err
}
defer func(archive *os.File) {
err := archive.Close()
if err != nil {
return
}
}(archive)
gr, err := gzip.NewReader(archive)
if err != nil {
return err
}
defer func(gr *gzip.Reader) {
err := gr.Close()
if err != nil {
return
}
}(gr)
tr := tar.NewReader(gr)
for {
f, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
filePath := path.Join(dst, f.Name)
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
if f.FileInfo().IsDir() {
err := os.MkdirAll(filePath, os.ModePerm)
if err != nil {
return err
}
continue
} else {
fileName := path.Join(dst, f.Name)
fw, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(f.Mode))
defer func(fw *os.File) {
err := fw.Close()
if err != nil {
return
}
}(fw)
if err != nil {
return err
}
if _, err := io.Copy(fw, tr); err != nil {
return err
}
}
}
return nil
}
解压tar.gz文件到指定目录,不包含顶层文件夹,只是将文件解压到指定目录
这种适合压缩文件带了顶层文件夹,但是解压后不想要顶层文件夹的情况
package tar
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"path"
"path/filepath"
"strings"
)
type TGZHandler struct {
}
func NewTGZHandler() *TGZHandler {
return &TGZHandler{}
}
func (z *TGZHandler) UNTarGZTo(src, dst string) error {
archive, err := os.Open(src)
if err != nil {
return err
}
defer func(archive *os.File) {
err := archive.Close()
if err != nil {
return
}
}(archive)
gr, err := gzip.NewReader(archive)
if err != nil {
return err
}
defer func(gr *gzip.Reader) {
err := gr.Close()
if err != nil {
return
}
}(gr)
tr := tar.NewReader(gr)
for {
f, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
filePath := path.Join(dst, f.Name)
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
if f.FileInfo().IsDir() {
err := os.MkdirAll(filePath, os.ModePerm)
if err != nil {
return err
}
continue
} else {
splitPath := strings.Split(f.Name, string(os.PathSeparator))
targetPath := strings.Join(splitPath[1:], string(os.PathSeparator))
filePath := filepath.Join(dst, targetPath)
fw, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(f.Mode))
defer func(fw *os.File) {
err := fw.Close()
if err != nil {
return
}
}(fw)
if err != nil {
return err
}
if _, err := io.Copy(fw, tr); err != nil {
return err
}
}
}
return nil
}
压缩tar.gz文件
Golang 中可以使用 archive/tar 和 compress/gzip 包来将文件夹压缩为 .tar.gz 文件。以下是一个示例程序,演示如何将文件夹压缩为 .tar.gz 文件:
package main
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"path/filepath"
)
func main() {
// 创建一个新的 .tar.gz 文件
file, err := os.Create("test.tar.gz")
if err != nil {
panic(err)
}
defer file.Close()
// 创建一个 gzip.Writer
gzipWriter := gzip.NewWriter(file)
defer gzipWriter.Close()
// 创建一个 tar.Writer
tarWriter := tar.NewWriter(gzipWriter)
defer tarWriter.Close()
// 遍历要压缩的文件夹
dir := "./test"
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
// 如果是文件夹或者无法读取文件信息,则忽略
if info.IsDir() || err != nil {
return nil
}
// 打开文件
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
// 创建一个新的 tar 文件头
header := new(tar.Header)
header.Name = path
header.Size = info.Size()
header.Mode = int64(info.Mode())
header.ModTime = info.ModTime()
// 将 tar 文件头写入到 tar 文件中
err = tarWriter.WriteHeader(header)
if err != nil {
return err
}
// 将文件内容写入到 tar 文件中
_, err = io.Copy(tarWriter, file)
if err != nil {
return err
}
return nil
})
}
该示例程序将指定的文件夹(“./test”)中的所有文件压缩到一个名为 “test.tar.gz” 的 .tar.gz 文件中。程序首先创建一个新的 .tar.gz 文件,并创建一个 gzip.Writer 和一个 tar.Writer。然后遍历要压缩的文件夹,对于每个文件,打开文件,创建一个新的 tar 文件头(tar.Header),并将文件内容写入到 tar 文件中,最后关闭 tar.Writer 和 gzip.Writer
如何判断文件是zip压缩的还是tgz压缩的
要判断文件是 ZIP 压缩还是 TGZ 压缩,可以使用文件格式识别库 libmagic,或者根据文件后缀名来判断。以下是两种方法的示例代码:
使用 libmagic 库判断文件类型:
package main
import (
"fmt"
"github.com/rakyll/magicmime"
"os"
)
func main() {
fileName := "test.zip"
// 创建 magicmime 实例
magic := magicmime.NewMagicMime("magic.mime")
// 打开文件
file, err := os.Open(fileName)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
// 判断文件类型
fileType, err := magic.TypeByFile(fileName)
if err != nil {
fmt.Println(err)
return
}
if fileType == "Zip archive data, at least v2.0 to extract" {
fmt.Println("文件类型:ZIP")
} else if fileType == "gzip compressed data, from Unix" {
fmt.Println("文件类型:TGZ")
} else {
fmt.Printf("未知文件类型:%s\n", fileType)
}
}
该示例程序使用 go-magic 库来判断文件类型,并根据文件类型输出相应的信息。如果文件类型是 Zip 压缩,输出“文件类型:ZIP”,如果是 TGZ 压缩,输出“文件类型:TGZ”,否则输出“未知文件类型:文件类型”
根据文件后缀名判断文件类型:
package main
import (
"fmt"
"strings"
)
func main() {
fileName := "test.zip"
// 获取文件后缀名
fileExt := strings.ToLower(fileName[strings.LastIndex(fileName, ".")+1:])
if fileExt == "zip" {
fmt.Println("文件类型:ZIP")
} else if fileExt == "tgz" || fileExt == "tar.gz" {
fmt.Println("文件类型:TGZ")
} else {
fmt.Printf("未知文件类型:%s\n", fileExt)
}
}
该示例程序根据文件后缀名来判断文件类型,并输出相应的信息。如果文件后缀名是 zip,输出“文件类型:ZIP”,如果是 tgz 或 tar.gz,输出“文件类型:TGZ”,否则输出“未知文件类型:文件后缀名”
如何判断给定的文件是哪种文件类型
可以使用 http.DetectContentType()
函数来判断给定的文件类型。该函数会根据文件内容的前几个字节来判断文件类型。
以下是一个示例代码,可以判断文件类型并输出文件类型:
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
fileName := "test.jpg"
// 打开文件
file, err := os.Open(fileName)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
// 读取文件内容的前512个字节
buffer := make([]byte, 512)
_, err = file.Read(buffer)
if err != nil {
fmt.Println(err)
return
}
// 判断文件类型
fileType := http.DetectContentType(buffer)
fmt.Printf("文件类型: %s\n", fileType)
}
该示例程序首先打开指定的文件,并读取文件内容的前512个字节。然后,它使用 http.DetectContentType()
函数来判断文件类型,并输出文件类型
请注意,http.DetectContentType()
函数并不是百分之百准确的,因为它只是根据文件内容的前几个字节来判断文件类型。在一些特殊情况下,该函数可能会判断错误
将一个100g的文件以5g为单位压缩为20个子zip包
在Go语言中,可以使用标准库中的archive/zip
和io
包来实现将一个大文件分割为多个子Zip包的功能。以下是一个示例代码:
package main
import (
"archive/zip"
"fmt"
"io"
"os"
)
func main() {
filePath := "largefile.bin" // 待压缩的大文件路径
chunkSize := int64(5 * 1024 * 1024 * 1024) // 每个子Zip包的大小,这里设置为5GB
targetDir := "target" // 保存子Zip包的目标文件夹路径
// 打开大文件
file, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer file.Close()
// 获取大文件的大小
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
fileSize := fileInfo.Size()
// 计算需要分割成多少个子Zip包
numChunks := fileSize / chunkSize
if fileSize % chunkSize != 0 {
numChunks++
}
// 创建目标文件夹
os.MkdirAll(targetDir, os.ModePerm)
// 分割大文件并保存为多个子Zip包
for i := int64(0); i < numChunks; i++ {
start := i * chunkSize
end := (i + 1) * chunkSize
if end > fileSize {
end = fileSize
}
// 创建子Zip包的文件名
zipFileName := fmt.Sprintf("%s/part-%02d.zip", targetDir, i)
// 创建子Zip包
zipFile, err := os.Create(zipFileName)
if err != nil {
panic(err)
}
defer zipFile.Close()
// 创建Zip Writer
zipWriter := zip.NewWriter(zipFile)
// 将大文件的一部分写入Zip包中
fileChunk := make([]byte, end-start)
_, err = file.ReadAt(fileChunk, start)
if err != nil && err != io.EOF {
panic(err)
}
// 创建Zip包中的文件
zipEntryName := fmt.Sprintf("part-%02d.bin", i)
zipEntry, err := zipWriter.Create(zipEntryName)
if err != nil {
panic(err)
}
// 写入Zip包中的文件内容
_, err = zipEntry.Write(fileChunk)
if err != nil {
panic(err)
}
// 关闭Zip Writer
err = zipWriter.Close()
if err != nil {
panic(err)
}
fmt.Printf("已创建子Zip包:%s\n", zipFileName)
}
fmt.Println("分割完成")
}
在上面的代码中,我们首先使用os.Open
函数打开待压缩的大文件,然后使用file.Stat()
函数获取文件的大小。接着,我们根据每个子Zip包的大小,计算需要将大文件分割成多少个子Zip包。然后,我们创建一个目标文件夹来保存子Zip包。
接下来,我们使用一个循环来分割大文件并将每个子文件保存为一个Zip包。对于每个子文件,我们首先创建一个子Zip包的文件名,然后创建一个Zip Writer来写入Zip包中的文件。我们使用file.ReadAt
函数读取大文件中的一部分数据,并将其写入Zip包中的文件。最后,我们关闭Zip Writer,并输出一条信息,表示已经创建子Zip包。
最终,当所有子Zip包都创建完成后,我们输出一条信息,表示分割完成
将上面20个zip子包合并为一个原始zip文件
package main
import (
"archive/zip"
"fmt"
"io"
"os"
"path/filepath"
)
const (
zipFileName = "merged.zip"
)
func main() {
// 创建一个新的zip文件
newZipFile, err := os.Create(zipFileName)
if err != nil {
fmt.Println(err)
return
}
defer newZipFile.Close()
// 创建一个zip写入器
zipWriter := zip.NewWriter(newZipFile)
defer zipWriter.Close()
// 遍历所有zip子包文件
for i := 0; i < 20; i++ {
zipFileName := fmt.Sprintf("file_%d.zip", i+1)
// 打开zip子包文件
zipFile, err := os.Open(zipFileName)
if err != nil {
fmt.Println(err)
return
}
defer zipFile.Close()
// 获取zip子包文件的文件信息
info, err := zipFile.Stat()
if err != nil {
fmt.Println(err)
return
}
// 创建一个zip文件头
header, err := zip.FileInfoHeader(info)
if err != nil {
fmt.Println(err)
return
}
// 设置zip文件头的名称
header.Name = filepath.Base(zipFileName)
// 向zip文件中写入zip文件头
writer, err := zipWriter.CreateHeader(header)
if err != nil {
fmt.Println(err)
return
}
// 将zip子包文件的内容写入到新的zip文件中
_, err = io.Copy(writer, zipFile)
if err != nil {
fmt.Println(err)
return
}
}
fmt.Printf("合并完成,新的zip文件名为:%s\n", zipFileName)
}
在这个示例程序中,我们首先创建了一个新的zip文件merged.zip
,然后通过创建zip.Writer
来写入zip文件。接着,我们遍历所有的zip子包文件,打开每个zip子包文件,读取文件信息并创建一个新的zip文件头,然后将zip子包文件的内容写入到新的zip文件中。最后,我们输出合并后的zip文件名并结束程序
请注意,这个示例程序仅适用于zip子包文件中的所有文件都位于根目录下的情况。如果zip子包文件中包含子目录,你可能需要修改代码以正确处理这些文件
🏠 回到主页