Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Cara mengemas dan memampatkan fail dalam Go

Cara mengemas dan memampatkan fail dalam Go

Go语言进阶学习
Go语言进阶学习ke hadapan
2023-07-21 11:14:381115semak imbas
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|
+----------------------------------------+
| ...                                     |

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

archive/tar

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."},
 }
 ... 
}

接着依次构建文件头信息,分别指定了文件名、权限和大小(可定义更多文件头字段),再通过<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)
  }
 }
}

执行以上代码,将得到打包后的 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

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

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

$ tar -xvf out.tar
x readme.txt
x gopher.txt
x todo.txt

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

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.

首先需要打开 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()
 ...
}

非常简单!只需要将<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

同理,如果要解压并解包 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)
  ...
}

依然很简单!只需要将<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!

Kenyataan:
Artikel ini dikembalikan pada:Go语言进阶学习. Jika ada pelanggaran, sila hubungi admin@php.cn Padam