欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Go語言實(shí)現(xiàn)壓縮文件處理

 更新時間:2024年11月29日 08:53:55   作者:熬了夜的程序員  
在現(xiàn)代的應(yīng)用開發(fā)中,處理壓縮文件(如 .zip 格式)是常見的需求,本文將介紹如何使用 Go 語言封裝一個 ziputil 包,來處理文件的壓縮和解壓操作,需要的可以了解下

Go 語言壓縮文件處理

在現(xiàn)代的應(yīng)用開發(fā)中,處理壓縮文件(如 .zip 格式)是常見的需求。Go 語言提供了內(nèi)置的 archive/zip 包來處理 .zip 文件的讀寫,但有時我們需要封裝一些常用操作,使得代碼更加簡潔、易用。本文將介紹如何使用 Go 語言封裝一個 ziputil 包,來處理文件的壓縮和解壓操作。

1. 壓縮文件:Zip函數(shù)

在 Go 語言中,壓縮文件通常需要使用 archive/zip 包。我們將對文件夾或文件進(jìn)行遍歷,創(chuàng)建一個新的 .zip 文件,并將文件或文件夾逐個添加到壓縮包中。

package ziputil

import (
	"archive/zip"
	"go-admin/app/brush/utils"
	"sync"
	"io"
	"os"
	"path/filepath"
	log "github.com/go-admin-team/go-admin-core/logger"
)

// Zip 將指定的文件夾或文件壓縮為 .zip 文件
func Zip(source, zipFile string) error {
	// 創(chuàng)建一個新的 zip 文件
	zipFileWriter, err := os.Create(zipFile)
	if err != nil {
		return err
	}
	defer func(zipFileWriter *os.File) {
		err := zipFileWriter.Close()
		if err != nil {
			log.Errorf("關(guān)閉 zip 文件失敗: %s", err)
		}
	}(zipFileWriter)

	// 創(chuàng)建 zip 寫入器
	zipWriter := zip.NewWriter(zipFileWriter)
	defer func(zipWriter *zip.Writer) {
		err := zipWriter.Close()
		if err != nil {
			log.Errorf("關(guān)閉 zip 寫入器失敗: %s", err)
		}
	}(zipWriter)

	// 獲取源文件的絕對路徑
	absSource, err := filepath.Abs(source)
	if err != nil {
		return err
	}

	// 遍歷文件夾并添加到 zip 文件中
	return filepath.Walk(absSource, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 計算文件相對路徑
		relPath, err := filepath.Rel(absSource, path)
		if err != nil {
			return err
		}

		// 如果是目錄,則在 zip 文件中創(chuàng)建一個目錄項(xiàng)
		if info.IsDir() {
			if relPath != "." {
				_, err := zipWriter.Create(relPath + "/")
				if err != nil {
					return err
				}
			}
			return nil
		}

		// 否則將文件添加到 zip 文件
		return addFileToZip(zipWriter, path, relPath)
	})
}

// addFileToZip 將單個文件添加到 zip 寫入器
func addFileToZip(zipWriter *zip.Writer, file string, relPath string) error {
	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer func(f *os.File) {
		err := f.Close()
		if err != nil {
			log.Errorf("關(guān)閉文件失敗: %s", err)
		}
	}(f)

	// 在 zip 文件中創(chuàng)建該文件
	writer, err := zipWriter.Create(relPath)
	if err != nil {
		return err
	}

	// 將文件內(nèi)容寫入 zip
	_, err = io.Copy(writer, f)
	if err != nil {
		return err
	}

	return nil
}

2. 解壓文件:UnZip 函數(shù)

解壓 .zip 文件時,我們需要將 .zip 文件中的每個文件提取到指定的目錄中。UnZip 函數(shù)不僅能夠提取文件,還能夠處理文件夾結(jié)構(gòu),保證提取后的目錄結(jié)構(gòu)不丟失。

// UnZip 解壓 zip 文件到目標(biāo)目錄
func UnZip(zipFile, destDir string) error {
	log.Debugf("解壓文件: %s 到 %s", zipFile, destDir)
	r, err := zip.OpenReader(zipFile)
	if err != nil {
		return err
	}

	defer func(r *zip.ReadCloser) {
		err := r.Close()
		if err != nil {
			log.Errorf("關(guān)閉 zip 文件失敗: %s", err)
		}
	}(r)

	log.Debugf("總共 %d 個文件", len(r.File))

	// 并發(fā)解壓每個文件
	wg := sync.WaitGroup{}
	for _, f := range r.File {
		wg.Add(1)
		go func(rf *zip.File, w *sync.WaitGroup) {
			defer w.Done()
			if err := unzipFile(rf, destDir); err != nil {
				log.Errorf("解壓文件 [%s] 失敗: %v", rf.Name, err)
			}
		}(f, &wg)
	}

	wg.Wait()

	return nil
}

// unzipFile 解壓單個文件到目標(biāo)目錄
func unzipFile(f *zip.File, destDir string) error {
	// 將文件名轉(zhuǎn)換為 UTF-8
	filename := utils.ConvertToUTF8([]byte(f.Name))
	filePath := filepath.Join(destDir, filename)

	// 創(chuàng)建文件夾
	if f.FileInfo().IsDir() {
		return os.MkdirAll(filePath, os.ModePerm)
	}

	// 創(chuàng)建文件的父目錄
	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
		log.Errorf("創(chuàng)建目錄 [%s] 失敗: %v", filepath.Dir(filePath), err)
		return err
	}

	// 打開文件
	file, err := f.Open()
	if err != nil {
		log.Errorf("打開文件 [%s] 失敗: %v", filePath, err)
		return err
	}

	defer func(file io.ReadCloser) {
		err := file.Close()
		if err != nil {
			log.Errorf("關(guān)閉文件 [%s] 失敗: %v", filePath, err)
		}
	}(file)

	// 創(chuàng)建文件
	outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
	if err != nil {
		log.Errorf("創(chuàng)建文件 [%s] 失敗: %v", filePath, err)
		return err
	}

	defer func(outFile *os.File) {
		err := outFile.Close()
		if err != nil {
			log.Errorf("關(guān)閉文件 [%s] 失敗: %v", filePath, err)
		}
	}(outFile)

	// 將文件內(nèi)容寫入
	_, err = io.Copy(outFile, file)
	if err != nil {
		log.Errorf("復(fù)制文件 [%s] 失敗: %v", filePath, err)
		return err
	}

	return nil
}

3. 小結(jié)

通過 ziputil 包,我們可以方便地進(jìn)行文件和文件夾的壓縮和解壓操作。該包使用了 Go 內(nèi)置的 archive/zip 包來處理 .zip 文件,并通過 sync.WaitGroup 實(shí)現(xiàn)了解壓過程的并發(fā)處理,提高了解壓效率。對于較大的壓縮文件或包含大量文件的壓縮包,使用并發(fā)處理可以顯著提升性能。

到此這篇關(guān)于基于Go語言實(shí)現(xiàn)壓縮文件處理的文章就介紹到這了,更多相關(guān)Go壓縮文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go可變參數(shù)函數(shù)的實(shí)現(xiàn)

    Go可變參數(shù)函數(shù)的實(shí)現(xiàn)

    可變參數(shù)函數(shù)是指函數(shù)參數(shù)的某個參數(shù)可有可無,即這個參數(shù)的個數(shù)可以為0會多個,可變參數(shù)函數(shù)參數(shù)在日常編程中大量使用,本文主要介紹了Go可變參數(shù)函數(shù)的實(shí)現(xiàn),感興趣的可以了解一下
    2023-12-12
  • 詳解go 動態(tài)數(shù)組 二維動態(tài)數(shù)組

    詳解go 動態(tài)數(shù)組 二維動態(tài)數(shù)組

    這篇文章主要介紹了go 動態(tài)數(shù)組 二維動態(tài)數(shù)組,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • 詳解Go中Set的實(shí)現(xiàn)方式

    詳解Go中Set的實(shí)現(xiàn)方式

    這篇文章主要介紹了詳解Go中Set的實(shí)現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 一文帶大家搞懂Go語言中的迭代器

    一文帶大家搞懂Go語言中的迭代器

    迭代器是使用戶可在容器對象上遍訪的對象,設(shè)計人員使用此接口無需關(guān)心容器對象的內(nèi)存分配的實(shí)現(xiàn)細(xì)節(jié),本文主要為大家詳細(xì)介紹一下Go語言中的迭代器的實(shí)現(xiàn),需要的可以了解下
    2025-02-02
  • Golang環(huán)境變量設(shè)置和查看工具go env詳解

    Golang環(huán)境變量設(shè)置和查看工具go env詳解

    go env 是 Go 工具鏈中的一個命令,用于設(shè)置和查看當(dāng)前 Golang 環(huán)境的相關(guān)信息,對于理解、編譯和運(yùn)行 Golang 程序非常有用,本文就給大家簡單的介紹一下Golang環(huán)境變量設(shè)置和查看工具go env,需要的朋友可以參考下
    2023-07-07
  • 深入淺出Golang中的sync.Pool

    深入淺出Golang中的sync.Pool

    sync.Pool是可伸縮的,也是并發(fā)安全的,其大小僅受限于內(nèi)存大小。本文主要為大家介紹一下Golang中sync.Pool的原理與使用,感興趣的小伙伴可以了解一下
    2023-03-03
  • Go語言中sync.Cond使用詳解

    Go語言中sync.Cond使用詳解

    本文主要介紹了Go語言中sync.Cond使用詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Go語言中使用gorm小結(jié)

    Go語言中使用gorm小結(jié)

    這篇文章主要給大家介紹了Go語言中如何使用gorm,文中介紹的很詳細(xì),有需要的朋友們可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • go中值傳遞和指針傳遞的使用

    go中值傳遞和指針傳遞的使用

    在Go語言中,使用&和*可以分別取得變量的地址和值,解引用未初始化或?yàn)閚il的指針會引發(fā)空指針異常,正確的做法是先進(jìn)行nil檢查,此外,nil在Go中用于多種類型的空值表示,值傳遞和指針傳遞各有適用場景,通常小型數(shù)據(jù)結(jié)構(gòu)優(yōu)先考慮值傳遞以減少解引用開銷
    2024-10-10
  • Go Gin框架中的binding驗(yàn)證器使用小結(jié)

    Go Gin框架中的binding驗(yàn)證器使用小結(jié)

    Gin框架中的binding驗(yàn)證器為我們提供了簡便的數(shù)據(jù)綁定和驗(yàn)證功能,通過合理使用binding和validate標(biāo)簽,我們可以確保API接口的數(shù)據(jù)合法性和完整性,這篇文章主要介紹了Go Gin框架中的binding驗(yàn)證器使用指南,需要的朋友可以參考下
    2024-07-07

最新評論