Go で lz4 アルゴリズムを使用してファイルを圧縮および解凍したいと考えています。これを行うためのパッケージはありますか? https://github.com/pierrec/lz4というパッケージを検索して見つけました
Go 初心者で、このパッケージを使用してファイルを圧縮および解凍する方法がわかりません。
このパッケージを使用してファイルをバイナリ形式に圧縮し、Go を使用してバイナリ ファイルを元のファイルに解凍する必要があります。
Go で lz4 アルゴリズムを使用してファイルを圧縮および解凍したいと考えています。これを行うためのパッケージはありますか? https://github.com/pierrec/lz4というパッケージを検索して見つけました
Go 初心者で、このパッケージを使用してファイルを圧縮および解凍する方法がわかりません。
このパッケージを使用してファイルをバイナリ形式に圧縮し、Go を使用してバイナリ ファイルを元のファイルに解凍する必要があります。
bufio パッケージを使用すると、ファイルの内容全体を一度にメモリに丸呑みすることなく、ファイルを圧縮 (解凍) できます。
実際には、これにより、システムで使用可能なメモリよりも大きなファイルを圧縮 (解凍) することができます。これは、特定の状況に関連する場合と関連しない場合があります。
これが関連する場合は、ここで実際の例を見つけることができます:
package main
import (
"bufio"
"io"
"os"
"github.com/pierrec/lz4"
)
// Compress a file, then decompress it again!
func main() {
compress("./compress-me.txt", "./compressed.txt")
decompress("./compressed.txt", "./decompressed.txt")
}
func compress(inputFile, outputFile string) {
// open input file
fin, err := os.Open(inputFile)
if err != nil {
panic(err)
}
defer func() {
if err := fin.Close(); err != nil {
panic(err)
}
}()
// make a read buffer
r := bufio.NewReader(fin)
// open output file
fout, err := os.Create(outputFile)
if err != nil {
panic(err)
}
defer func() {
if err := fout.Close(); err != nil {
panic(err)
}
}()
// make an lz4 write buffer
w := lz4.NewWriter(fout)
// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
for {
// read a chunk
n, err := r.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
// write a chunk
if _, err := w.Write(buf[:n]); err != nil {
panic(err)
}
}
if err = w.Flush(); err != nil {
panic(err)
}
}
func decompress(inputFile, outputFile string) {
// open input file
fin, err := os.Open(inputFile)
if err != nil {
panic(err)
}
defer func() {
if err := fin.Close(); err != nil {
panic(err)
}
}()
// make an lz4 read buffer
r := lz4.NewReader(fin)
// open output file
fout, err := os.Create(outputFile)
if err != nil {
panic(err)
}
defer func() {
if err := fout.Close(); err != nil {
panic(err)
}
}()
// make a write buffer
w := bufio.NewWriter(fout)
// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
for {
// read a chunk
n, err := r.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
// write a chunk
if _, err := w.Write(buf[:n]); err != nil {
panic(err)
}
}
if err = w.Flush(); err != nil {
panic(err)
}
}
結果私が期待したのは、以下のコードからのものです。これを入手しました [ https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fpierrec%2Flz4%2Fblob%2Fmaster%2Flz4c%2Fmain.go&sa=D&sntz=1&usg=AFQjCNFIT2O1Grs0vu4Gh8Af96GSBaa9EA ] からファイル。ファイルはコマンドライン引数の入力として与えられ、その圧縮/解凍が正常に行われました。
package main
import (
// "bytes"
"flag"
"fmt"
"io"
"log"
"os"
"path"
"runtime"
"strings"
"github.com/pierrec/lz4"
)
func main() {
// Process command line arguments
var (
blockMaxSizeDefault = 4 << 20
flagStdout = flag.Bool("c", false, "output to stdout")
flagDecompress = flag.Bool("d", false, "decompress flag")
flagBlockMaxSize = flag.Int("B", blockMaxSizeDefault, "block max size [64Kb,256Kb,1Mb,4Mb]")
flagBlockDependency = flag.Bool("BD", false, "enable block dependency")
flagBlockChecksum = flag.Bool("BX", false, "enable block checksum")
flagStreamChecksum = flag.Bool("Sx", false, "disable stream checksum")
flagHighCompression = flag.Bool("9", false, "enabled high compression")
)
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage:\n\t%s [arg] [input]...\n\tNo input means [de]compress stdin to stdout\n\n", os.Args[0])
flag.PrintDefaults()
}
flag.Parse()
fmt.Println("output to stdout ", *flagStdout)
fmt.Println("Decompress", *flagDecompress)
// Use all CPUs
runtime.GOMAXPROCS(runtime.NumCPU())
zr := lz4.NewReader(nil)
zw := lz4.NewWriter(nil)
zh := lz4.Header{
BlockDependency: *flagBlockDependency,
BlockChecksum: *flagBlockChecksum,
BlockMaxSize: *flagBlockMaxSize,
NoChecksum: *flagStreamChecksum,
HighCompression: *flagHighCompression,
}
worker := func(in io.Reader, out io.Writer) {
if *flagDecompress {
fmt.Println("\n Decompressing the data")
zr.Reset(in)
if _, err := io.Copy(out, zr); err != nil {
log.Fatalf("Error while decompressing input: %v", err)
}
} else {
zw.Reset(out)
zw.Header = zh
if _, err := io.Copy(zw, in); err != nil {
log.Fatalf("Error while compressing input: %v", err)
}
}
}
// No input means [de]compress stdin to stdout
if len(flag.Args()) == 0 {
worker(os.Stdin, os.Stdout)
os.Exit(0)
}
// Compress or decompress all input files
for _, inputFileName := range flag.Args() {
outputFileName := path.Clean(inputFileName)
if !*flagStdout {
if *flagDecompress {
outputFileName = strings.TrimSuffix(outputFileName, lz4.Extension)
if outputFileName == inputFileName {
log.Fatalf("Invalid output file name: same as input: %s", inputFileName)
}
} else {
outputFileName += lz4.Extension
}
}
inputFile, err := os.Open(inputFileName)
if err != nil {
log.Fatalf("Error while opening input: %v", err)
}
outputFile := os.Stdout
if !*flagStdout {
outputFile, err = os.Create(outputFileName)
if err != nil {
log.Fatalf("Error while opening output: %v", err)
}
}
worker(inputFile, outputFile)
inputFile.Close()
if !*flagStdout {
outputFile.Close()
}
}
}
サンプル入力
compress.go -9=true sample.txt を実行します。
私はGoも初めてで、を使用するのに少し苦労しましたgithub.com/pierrec/lz4
。
私が誤解していたのは、呼び出しはオプションClose()
でNewWriter
はなく、そうしないと誤った結果につながるということです。(ファイル ハンドラやネットワーク接続などを閉じる場合と同様に、これはオプションであり、単なるベスト プラクティスであると考えるために、壁に頭をぶつけるのに多くの時間を費やしました)
圧縮/解凍用の 2 つのラッパー バージョンを作成しました。
まず、一般的なリーダー/ライターのアプローチ (README の例に似ていますが、パイプはありません) [プレイグラウンド]:
func compress(r io.Reader, w io.Writer) error {
zw := lz4.NewWriter(w)
_, err := io.Copy(zw, r)
if err != nil {
return err
}
// Closing is *very* important
return zw.Close()
}
func decompress(r io.Reader, w io.Writer) error {
zr := lz4.NewReader(r)
_, err := io.Copy(w, zr)
return err
}
データサイズが小さく、バッファをいじる必要がなく、圧縮されていないバイトを入れ、圧縮されたバイトを出したい場合 (より「機能的な」方法で)、この 2 番目のバージョンの方が便利な場合があります [プレイグラウンド]:
func compress(in []byte) ([]byte, error) {
r := bytes.NewReader(in)
w := &bytes.Buffer{}
zw := lz4.NewWriter(w)
_, err := io.Copy(zw, r)
if err != nil {
return nil, err
}
// Closing is *very* important
if err := zw.Close(); err != nil {
return nil, err
}
return w.Bytes(), nil
}
func decompress(in []byte) ([]byte, error) {
r := bytes.NewReader(in)
w := &bytes.Buffer{}
zr := lz4.NewReader(r)
_, err := io.Copy(w, zr)
if err != nil {
return nil, err
}
return w.Bytes(), nil
}