>백엔드 개발 >Golang >Go에서 파일을 압축하고 압축하는 방법

Go에서 파일을 압축하고 압축하는 방법

Go语言进阶学习
Go语言进阶学习앞으로
2023-07-21 11:14:381174검색
파일 패키징, 압축 및 압축 해제는 자주 사용되는 기능입니다. tar 및 gzip과 같은 도구를 통해 이러한 작업을 완료할 수 있습니다. Go의 표준 라이브러리 <span style="font-size: 15px;">archive</span><span style="font-size: 15px;">compress</span>archive
compress

는 이러한 기능을 제공합니다. 이 기사의 예제를 통해 Go 프로그래밍을 사용하여 압축된 패키지 파일을 생성하고 처리하는 것이 매우 간단하다는 것을 알게 될 것입니다.

Packaging and Compression

🎜🎜🎜코드를 시작하기 전에 패키징과 압축의 개념을 명확히 해야 합니다. 🎜🎜
  • 아카이브라고도 하는 패키징은 파일이나 디렉터리의 모음을 말하며, 이 모음은 파일에 저장됩니다.
  • 압축이란 최대 파일 정보를 유지하고 파일 크기를 줄이기 위해 알고리즘을 사용하여 파일을 처리하는 것을 의미합니다.

패키징 도구 tar를 예로 들어 보겠습니다. tar로 생성된 파일은 일반적으로 tar 패키지라고 하며 파일 이름은 일반적으로 .tar로 끝납니다. 그런 다음 gzip 압축과 같은 다른 압축 도구를 통해 tar 패키지를 압축하면 일반적으로 .tar.gz라는 이름의 압축 파일을 얻게 됩니다(tar에서는 -z 매개변수를 사용하여 gzip을 호출할 수 있음).

tar 패키지는 파일의 집합이며 그 구조도 데이터 세그먼트로 구성됩니다. 각 데이터 세그먼트에는 파일 헤더(파일을 설명하는 메타정보)와 파일 내용이 포함됩니다.

+----------------------------------------+
| Header                                 |
| [name][mode][owner][group][size]  ...  |
+----------------------------------------+
| Content                                |
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
+----------------------------------------+
| Header                                 |
| [name][mode][owner][group][size]  ...  |
+----------------------------------------+
| Content                                |
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
+----------------------------------------+
| ...                                     |

아카이브 라이브러리 포장 및 풀기

archive 아카이브 라이브러리의 중국어 의미는 아카이브이며, 그 기능은 아카이브(패키지) 및 언팩(언팩)입니다. tar와 zip의 두 가지 솔루션을 제공하며 호출 경로는 <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/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;">archive/zip<span style="font-size: 15px;"></span></p>.

파일을 패키지하고 압축을 푸는 방법을 보여주기 위해 tar를 예로 들어 보겠습니다.

🎜🎜🎜먼저 out.tar라는 새로운 대상 패키징 파일을 생성한 후, 보관을 위한 readme.txt, gopher.txt, todo.txt 파일 데이터를 구성합니다. 🎜🎜
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 设计。

물론 종이에 할 줄만 알고, 자세하게 해봐야 알죠. 사용하지 않음 <span style="font-size: 15px;">archive</span><span style="font-size: 15px;">compress</span>archive

compress
🎜라이브러리 독자는 이 문서에서 사용되지 않은 솔루션을 사용하여 패키지 및 압축 파일을 처리해 볼 수 있습니다. 🎜🎜🎜🎜

위 내용은 Go에서 파일을 압축하고 압축하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 Go语言进阶学习에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제