Cara mengemas dan memampatkan fail dalam Go

Lepaskan: 2023-07-21 11:14:38
ke hadapan
1114 orang telah melayarinya
Pembungkusan, pemampatan dan penyahmampatan fail adalah fungsi yang kerap digunakan. Kami boleh menyelesaikan operasi ini melalui alatan seperti tar dan gzip. Dalam Go, perpustakaan standard <span style="font-size: 15px;">archive</span><span style="font-size: 15px;">compress</span>arkib dan
compress

memberikan kami keupayaan ini. Melalui contoh dalam artikel ini, anda akan mendapati bahawa sangat mudah untuk menjana dan memproses fail pakej termampat menggunakan pengaturcaraan Go.

Pembungkusan dan Mampatan

🎜🎜🎜Sebelum memulakan kod, kita perlu menjelaskan konsep pembungkusan dan pemampatan. 🎜🎜
  • Pembungkusan, juga dikenali sebagai arkib, merujuk kepada koleksi fail atau direktori, dan koleksi ini disimpan dalam fail.
  • Mampatan merujuk kepada penggunaan algoritma untuk memproses fail untuk mengekalkan maklumat fail maksimum dan mengurangkan saiz fail.

Ambil tar alat pembungkusan sebagai contoh Fail yang dihasilkan olehnya biasanya dipanggil pakej tar, dan nama failnya biasanya berakhir dengan .tar. Kemudian mampatkan pakej tar melalui alat pemampatan lain, seperti pemampatan gzip, dan anda akan mendapat fail mampat yang biasanya dinamakan dengan .tar.gz (gzip boleh dipanggil dengan parameter -z dalam tar). Pakej tar ialah koleksi fail, dan strukturnya juga terdiri daripada segmen data Setiap segmen data mengandungi pengepala fail (metamaklumat yang menerangkan fail) dan kandungan fail.

+----------------------------------------+
| Header                                 |
| [name][mode][owner][group][size]  ...  |
+----------------------------------------+
| Content                                |
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
+----------------------------------------+
| Header                                 |
| [name][mode][owner][group][size]  ...  |
+----------------------------------------+
| Content                                |
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
+----------------------------------------+
| ...                                     |
Salin selepas log masuk

arkibkan pembungkusan dan pembongkaran perpustakaan

arkib Maksud bahasa Cina perpustakaan arkib ialah arkib, dan fungsinya adalah untuk mengarkibkan (membungkus) dan membongkar (membongkar). Ia menyediakan dua penyelesaian: tar dan zip, dan laluan panggilan ialah </h2>archive/tar<p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"> dan <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">archive/tar</span><span style="font-size: 15px;">archive/zip</span>archive/zip.

Kami mengambil tar sebagai contoh untuk menunjukkan cara membungkus dan membongkar fail.

Mula-mula, buat fail pembungkusan sasaran baharu sebagai out.tar, dan kemudian bina beberapa data fail readme.txt, gopher.txt dan todo.txt untuk pengarkiban.

🎜
import (
 "archive/tar"
  ...
)
func main() {
 // Create and add some files to the archive.
 tarPath := "out.tar"
 tarFile, err := os.Create(tarPath)
 if err != nil {
  log.Fatal(err)
 }
 defer tarFile.Close()
 tw := tar.NewWriter(tarFile)
 defer tw.Close()
 var files = []struct {
  Name, Body string
 }{
  {"readme.txt", "This archive contains some text files."},
  {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
  {"todo.txt", "Get animal handling license."},
 }
 ... 
}
Salin selepas log masuk

接着依次构建文件头信息,分别指定了文件名、权限和大小(可定义更多文件头字段),再通过<span style="font-size: 15px;">*tar.Writer</span>类型的 tw 变量,按序调用<span style="font-size: 15px;">WriteHeader</span><span style="font-size: 15px;">Write</span>方法将需要打包的数据段(文件头+文件内容)写入到out.tar文件。

 ...
 for _, file := range files {
  hdr := &tar.Header{
   Name: file.Name,
   Mode: 0600,
   Size: int64(len(file.Body)),
  }
  if err := tw.WriteHeader(hdr); err != nil {
   log.Fatal(err)
  }
  if _, err := tw.Write([]byte(file.Body)); err != nil {
   log.Fatal(err)
  }
 }
}
Salin selepas log masuk

执行以上代码,将得到打包后的 out.tar 文件,可通过 tar 工具指定 -tvf 参数查看归档信息。

$ tar -tvf out.tar
-rw-------  0 0      0          38 Jan  1  1970 readme.txt
-rw-------  0 0      0          35 Jan  1  1970 gopher.txt
-rw-------  0 0      0          28 Jan  1  1970 todo.txt
Salin selepas log masuk

可以看到,指定的文件信息(文件名、权限和大小)符合预期,但其他未指定的元信息是有误的,例如日期(直接给的默认值)。

如果通过 tar 工具,我们可以执行以下命令来提取 out.tar 中的文件。

$ tar -xvf out.tar
x readme.txt
x gopher.txt
x todo.txt
Salin selepas log masuk

但在程序中实现,应该怎么做呢?

func main() {
 tarPath := "out.tar"
 tarFile, err := os.Open(tarPath)
 if err != nil {
  log.Fatal(err)
 }
 defer tarFile.Close()
 tr := tar.NewReader(tarFile)
 for {
  hdr, err := tr.Next()
  // End of archive
  if err == io.EOF {
   break
  }
  if err != nil {
   log.Fatal(err)
  }
  fmt.Printf("Contents of %s: ", hdr.Name)
  if _, err := io.Copy(os.Stdout, tr); err != nil {
   log.Fatal(err)
  }
  fmt.Println()
 }
}

// Output:
Contents of readme.txt: This archive contains some text files.
Contents of gopher.txt: Gopher names:
George
Geoffrey
Gonzo
Contents of todo.txt: Get animal handling license.
Salin selepas log masuk

首先需要打开 out.tar,并构造<span style="font-size: 15px;">*tar.Reader</span>类型的 tr 变量。之后,利用<span style="font-size: 15px;">tr.Next</span>依次提取每个数据段内容,并通过 io.Copy(os.Stdout, tr),将文件内容拷贝至标准输出。直到<span style="font-size: 15px;">tr.Next</span>遇到<span style="font-size: 15px;">io.EOF</span>,它代表读取到了归档文件末尾,则退出提取。

compress 库压缩与解压缩

compress 库中支持了多种压缩方案,包括 bzip2、flate、gzip、lzw 和 zlib,调用路径为<span style="font-size: 15px;">compress/xxx</span>

我们以常用的 gzip 为例,来展示压缩与解压缩代码。

如果同样是上文中的文件数据 readme.txt、gopher.txt 和 todo.txt,我们想得到 tar 归档且被压缩了的 out.tar.gz 文件,应该如何做呢?

package main

import (
 "archive/tar"
 "compress/gzip"
 ...
)

func main() {
 tarPath := "out.tar.gz"
 tarFile, err := os.Create(tarPath)
 if err != nil {
  log.Fatal(err)
 }
 defer tarFile.Close()
 gz := gzip.NewWriter(tarFile)
 defer gz.Close()
 tw := tar.NewWriter(gz)
 defer tw.Close()
 ...
}
Salin selepas log masuk

非常简单!只需要将<span style="font-size: 15px;">tar.NewWriter(tarFile)</span>改为<span style="font-size: 15px;">tar.NewWriter(gz)</span>即可,其中<span style="font-size: 15px;">gz</span>是由<span style="font-size: 15px;">gzip.NewWriter(tarFile)</span> 而来。

我们比较有压缩与无压缩的归档 tar 包大小,可以看到文件体积从4.0K压缩为了224B。

$ ls -alh out.tar out.tar.gz
-rw-r--r--  1 slp  staff   4.0K Jul  3 21:52 out.tar
-rw-r--r--  1 slp  staff   224B Jul  3 21:53 out.tar.gz
Salin selepas log masuk

同理,如果要解压并解包 out.tar.gz 文件,应该如何做呢?

package main

import (
 "archive/tar"
 "compress/gzip"
  ...
)

func main() {
 tarPath := "out.tar.gz"
 tarFile, err := os.Open(tarPath)
 if err != nil {
  log.Fatal(err)
 }
 defer tarFile.Close()
 gz, err := gzip.NewReader(tarFile)
 if err != nil {
  log.Fatal(err)
 }
  defer gz.Close()
 tr := tar.NewReader(gz)
  ...
}
Salin selepas log masuk

依然很简单!只需要将<span style="font-size: 15px;">tar.NewReader(tarFile)</span>改为<span style="font-size: 15px;">tar.NewReader(gz)</span>即可,其中<span style="font-size: 15px;">gz</span>是由<span style="font-size: 15px;">gzip.NewReader(tarFile)</span> 而来。

总结

本文展示了如何通过archive/tar包实现文件的打包与解包操作,如何通过<span style="font-size: 15px;">compress/gzip</span>包对tar包开展进一步的压缩与解压缩。

在展示<span style="font-size: 15px;">compress/gzip</span>使用时,多封装一层Writer/Reader,即可为tar归档文件增加压缩与解压缩功能。更棒的是,如果你想切换打包/解包、压缩/解压缩策略,仅仅替换掉对应的 Writer/Reader 即可。而这种便利,源于 Go 优秀的流式 IO 设计。

Sudah tentu saya hanya tahu perkara ini perlu dijalankan secara terperinci. Tidak pernah digunakan <span style="font-size: 15px;">archive</span><span style="font-size: 15px;">compress</span>archive dan

Atas ialah kandungan terperinci Cara mengemas dan memampatkan fail dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
go
sumber:Go语言进阶学习
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan