golang中archive/tar包詳解
go語言官方標準庫提供tar庫,以方便對tar的操作
一、瞭解tar
什麼是tar?
tar是一種打包格式,但不對檔案進行壓縮,所以打包後的文件一般遠遠大於zip和tar.gz,因為不需要壓縮的原因,所以打包的速度是非常快的,打包時CPU佔用率也很低。
tar的目的是什麼?
方便檔案的管理(幫助理解:就是你存在很多檔案的時候,但是你很多要很長時間不去接觸的話,你想要變得更加簡潔,可以進行tar操作,就可以變得更簡潔,比如就像生活中,有很多小箱子分散在不同的房間裡,可以將小箱子疊起來放在一個房間裡,tar可以類似這樣)
下面一張圖可以幫助很好的理解

image.png
)
二、tar的操作
打包、解包
三、go如何對tar檔案操作
打包操作:
1、生成打包後的目標檔案
2、獲取要打包的檔案集
3、往目標檔案寫入檔案
接著給出一個程式碼案例:
package main import ( "log" "os" "archive/tar" "io" ) func main() { dst := "D:\\go_code\\video_server\\src\\a.tar" if err := Tar([]string{"D:\\go_code\\video_server\\src\\main.go", "D:\\go_code\\video_server\\src\\t.go"}, dst);err != nil { log.Fatal(err) } } func Tar(src []string, dst string) error { // 建立tar檔案 fw, err := os.Create(dst) if err != nil { return err } defer fw.Close() // 通過fw建立一個tar.Writer tw := tar.NewWriter(fw) // 如果關閉失敗會造成tar包不完整 defer func() { if err := tw.Close();err != nil { log.Println(err) } }() for _, fileName := range src { fi, err := os.Stat(fileName) if err != nil { log.Println(err) continue } hdr, err := tar.FileInfoHeader(fi, "") // 將tar的檔案資訊hdr寫入到tw err = tw.WriteHeader(hdr) if err != nil { return err } // 將檔案資料寫入 fs, err := os.Open(fileName) if err != nil { return err } if _, err = io.Copy(tw, fs);err != nil { return err } fs.Close() } return nil }
解包操作:
1、開啟tar檔案
2、遍歷tar中檔案資訊
3、建立檔案,寫入,儲存,關閉檔案
接著給出一個程式碼案例:
package main import ( "os" "log" "archive/tar" "io" ) func main() { srcFile := "a.tar" // 開啟 tar 包 fr, err := os.Open(srcFile) if err != nil { log.Fatal(err) } defer fr.Close() tr := tar.NewReader(fr) for hdr, err := tr.Next();err != io.EOF;hdr, err = tr.Next() { if err != nil { log.Println(err) continue } // 讀取檔案資訊 fi := hdr.FileInfo() // 建立一個空檔案,用來寫入解包後的資料 fw, err := os.Create(fi.Name()) if err != nil { log.Println(err) continue } if _, err := io.Copy(fw, tr);err != nil { log.Println(err) } os.Chmod(fi.Name(), fi.Mode().Perm()) fw.Close() } }
四、tar包深入學習(作為一名計算機專業人士,至少要知道原理和實現的,接著我們來分析下原理和實現)
打包和解包的原理和實現
1、打包實現原理
先建立一個檔案x.tar,然後向x.tar寫入tar頭部資訊。開啟要被tar的檔案,向x.tar寫入頭部資訊,然後向x.tar寫入檔案資訊。重複第二步直到所有檔案都被寫入到x.tar中,關閉x.tar,整個過程就這樣完成了
2、解包實現原理
先開啟tar檔案,然後從這個tar頭部中迴圈讀取儲存在這個歸檔檔案內的檔案頭資訊,從這個檔案頭裡讀取檔名,以這個檔名建立檔案,然後向這個檔案裡寫入資料
3、go標準庫解包實現程式碼詳解
打包: // 接下來對底層實現進行分析 tr := tar.NewReader(fr) hdr, err := tar.FileInfoHeader(fi, "") // 將tar的檔案資訊hdr寫入到tw err = tw.WriteHeader(hdr) 解包: fr, err := os.Open(srcFile) tr := tar.NewReader(fr) hdr, err := tr.Next() fi := hdr.FileInfo() fw, err := os.Create(fi.Name()) io.Copy(fw, tr) os.Chmod(fi.Name(), fi.Mode().Perm())
tar.NewReader、tar.FileInfoHeader、tw.WriteHeader(hdr)、tr.Next、hdr.FileInfo的實現在我下一篇文章中進行分析
// 看一遍程式碼可能不能深入理解,只有自己是實現一遍才能深入理解 // go 標準庫封裝windows、linux、FreeBSD、mac四類作業系統底層細節操作,因為不同的系統對檔案儲存方式不同,所以定義了下面這些常量 const ( // 型別 TypeReg= '0'// 普通檔案 TypeRegA= '\x00' // 普通檔案 TypeLink= '1'// 硬連結 TypeSymlink= '2'// 符號連結 TypeChar= '3'// 字元裝置節點 TypeBlock= '4'// 塊裝置節點 TypeDir= '5'// 目錄 TypeFifo= '6'// 先進先出佇列節點 TypeCont= '7'// 保留位 TypeXHeader= 'x'// 擴充套件頭 TypeXGlobalHeader = 'g'// 全域性擴充套件頭 TypeGNULongName= 'L'// 下一個檔案記錄有個長名字 TypeGNULongLink= 'K'// 下一個檔案記錄指向一個具有長名字的檔案 TypeGNUSparse= 'S'// 稀疏檔案 ) // 有四個變數,分別是寫內容太多,頭部資訊太長,關閉錯誤,以及無效tar頭部資訊 var ( ErrWriteTooLong= errors.New("archive/tar: write too long") ErrFieldTooLong= errors.New("archive/tar: header field too long") ErrWriteAfterClose = errors.New("archive/tar: write after close") ) var ( ErrHeader = errors.New("archive/tar: invalid tar header") ) type Header struct { Namestring// 記錄頭域的檔名 Modeint64// 許可權和模式位 Uidint// 所有者的使用者ID Gidint// 所有者的組ID Sizeint64// 位元組數(長度) ModTimetime.Time // 修改時間 Typeflagbyte// 記錄頭的型別 Linknamestring// 連結的目標名 Unamestring// 所有者的使用者名稱 Gnamestring// 所有者的組名 Devmajorint64// 字元裝置或塊裝置的major number Devminorint64// 字元裝置或塊裝置的minor number AccessTime time.Time // 訪問時間 ChangeTime time.Time // 狀態改變時間 Xattrsmap[string]string }
五、相關參考連結
Golang 學習筆記(四)- archive/tar 實現打包壓縮及解壓:
2)https://broqiang.com/posts/45
如果此文對你有稍許的幫助,謝謝點贊和關注,對go語言精通之路有興趣的可以加我qq:761774955,相互交流學習