github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/compress/flate/example_test.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package flate_test
     6  
     7  import (
     8  	"github.com/shogo82148/std/bytes"
     9  	"github.com/shogo82148/std/compress/flate"
    10  	"github.com/shogo82148/std/fmt"
    11  	"github.com/shogo82148/std/io"
    12  	"github.com/shogo82148/std/log"
    13  	"github.com/shogo82148/std/os"
    14  	"github.com/shogo82148/std/strings"
    15  	"github.com/shogo82148/std/sync"
    16  )
    17  
    18  // パフォーマンスの重要なアプリケーションでは、Reset を使用して現在の圧縮器または伸張器の状態を破棄し、
    19  // 以前に割り当てられたメモリを活用してそれらを迅速に再初期化することができます。
    20  func Example_reset() {
    21  	proverbs := []string{
    22  		"Don't communicate by sharing memory, share memory by communicating.\n",
    23  		"Concurrency is not parallelism.\n",
    24  		"The bigger the interface, the weaker the abstraction.\n",
    25  		"Documentation is for users.\n",
    26  	}
    27  
    28  	var r strings.Reader
    29  	var b bytes.Buffer
    30  	buf := make([]byte, 32<<10)
    31  
    32  	zw, err := flate.NewWriter(nil, flate.DefaultCompression)
    33  	if err != nil {
    34  		log.Fatal(err)
    35  	}
    36  	zr := flate.NewReader(nil)
    37  
    38  	for _, s := range proverbs {
    39  		r.Reset(s)
    40  		b.Reset()
    41  
    42  		// コンプレッサーをリセットし、入力ストリームからエンコードします。
    43  		zw.Reset(&b)
    44  		if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
    45  			log.Fatal(err)
    46  		}
    47  		if err := zw.Close(); err != nil {
    48  			log.Fatal(err)
    49  		}
    50  
    51  		// デコンプレッサをリセットし、いくつかの出力ストリームにデコードします。
    52  		if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
    53  			log.Fatal(err)
    54  		}
    55  		if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
    56  			log.Fatal(err)
    57  		}
    58  		if err := zr.Close(); err != nil {
    59  			log.Fatal(err)
    60  		}
    61  	}
    62  
    63  	// Output:
    64  	// Don't communicate by sharing memory, share memory by communicating.
    65  	// Concurrency is not parallelism.
    66  	// The bigger the interface, the weaker the abstraction.
    67  	// Documentation is for users.
    68  }
    69  
    70  // あらかじめ設定された辞書を使用すると、圧縮率を改善することができます。
    71  // 辞書を使用する際の難点は、圧縮機と展開機が事前に使用する辞書について合意する必要があるということです。
    72  func Example_dictionary() {
    73  
    74  	// 辞書はバイトの連続です。入力データを圧縮する際、圧縮器は辞書内で見つかった一致する部分文字列を代替しようとします。そのため、辞書には実際のデータストリームで見つかることが期待される部分文字列のみを含めるべきです。
    75  	const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
    76  
    77  	// 圧縮するデータには、辞書と一致する頻繁な(必要ではありませんが)部分文字列が含まれることが望ましいです。
    78  	const data = `<?xml version="1.0"?>
    79  <book>
    80  	<meta name="title" content="The Go Programming Language"/>
    81  	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
    82  	<meta name="published" content="2015-10-26"/>
    83  	<meta name="isbn" content="978-0134190440"/>
    84  	<data>...</data>
    85  </book>
    86  `
    87  
    88  	var b bytes.Buffer
    89  
    90  	// 特殊に作られた辞書を使用してデータを圧縮する。
    91  	zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
    92  	if err != nil {
    93  		log.Fatal(err)
    94  	}
    95  	if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
    96  		log.Fatal(err)
    97  	}
    98  	if err := zw.Close(); err != nil {
    99  		log.Fatal(err)
   100  	}
   101  
   102  	// 解凍プログラムは圧縮プログラムと同じ辞書を使用する必要があります。
   103  	// そうでないと、入力が破損しているように見えるかもしれません。
   104  	fmt.Println("Decompressed output using the dictionary:")
   105  	zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
   106  	if _, err := io.Copy(os.Stdout, zr); err != nil {
   107  		log.Fatal(err)
   108  	}
   109  	if err := zr.Close(); err != nil {
   110  		log.Fatal(err)
   111  	}
   112  
   113  	fmt.Println()
   114  
   115  	// 辞書のすべてのバイトを '#' に置き換えて、予め設定された辞書の近似効果を視覚的に示します。
   116  	fmt.Println("Substrings matched by the dictionary are marked with #:")
   117  	hashDict := []byte(dict)
   118  	for i := range hashDict {
   119  		hashDict[i] = '#'
   120  	}
   121  	zr = flate.NewReaderDict(&b, hashDict)
   122  	if _, err := io.Copy(os.Stdout, zr); err != nil {
   123  		log.Fatal(err)
   124  	}
   125  	if err := zr.Close(); err != nil {
   126  		log.Fatal(err)
   127  	}
   128  
   129  	// Output:
   130  	// Decompressed output using the dictionary:
   131  	// <?xml version="1.0"?>
   132  	// <book>
   133  	// 	<meta name="title" content="The Go Programming Language"/>
   134  	// 	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
   135  	// 	<meta name="published" content="2015-10-26"/>
   136  	// 	<meta name="isbn" content="978-0134190440"/>
   137  	// 	<data>...</data>
   138  	// </book>
   139  	//
   140  	// Substrings matched by the dictionary are marked with #:
   141  	// #####################
   142  	// ######
   143  	// 	############title###########The Go Programming Language"/#
   144  	// 	############authors###########Alan Donovan and Brian Kernighan"/#
   145  	// 	############published###########2015-10-26"/#
   146  	// 	############isbn###########978-0134190440"/#
   147  	// 	######...</#####
   148  	// </#####
   149  }
   150  
   151  // DEFLATEはネットワーク上で圧縮データを送信するのに適しています。
   152  func Example_synchronization() {
   153  	var wg sync.WaitGroup
   154  	defer wg.Wait()
   155  
   156  	// io.Pipeを使用してネットワーク接続をシミュレートします。
   157  	// 実際のネットワークアプリケーションでは、基礎となる接続を適切に閉じる必要があります。
   158  	rp, wp := io.Pipe()
   159  
   160  	// 送信機能として機能するために、ゴールーチンを開始します。
   161  	wg.Add(1)
   162  	go func() {
   163  		defer wg.Done()
   164  
   165  		zw, err := flate.NewWriter(wp, flate.BestSpeed)
   166  		if err != nil {
   167  			log.Fatal(err)
   168  		}
   169  
   170  		b := make([]byte, 256)
   171  		for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
   172  
   173  			// 最初のバイトがメッセージの長さであり、その後にメッセージ自体が続く、単純なフレーム形式を使用しています。
   174  			b[0] = uint8(copy(b[1:], m))
   175  
   176  			if _, err := zw.Write(b[:1+len(m)]); err != nil {
   177  				log.Fatal(err)
   178  			}
   179  
   180  			// Flushは、受信者がこれまでに送信されたすべてのデータを読み取ることができることを保証します。
   181  			if err := zw.Flush(); err != nil {
   182  				log.Fatal(err)
   183  			}
   184  		}
   185  
   186  		if err := zw.Close(); err != nil {
   187  			log.Fatal(err)
   188  		}
   189  	}()
   190  
   191  	// 受信者として動作するゴルーチンを開始する。
   192  	wg.Add(1)
   193  	go func() {
   194  		defer wg.Done()
   195  
   196  		zr := flate.NewReader(rp)
   197  
   198  		b := make([]byte, 256)
   199  		for {
   200  
   201  			// メッセージの長さを読み取ります。
   202  			// これは送信側のFlushとCloseに対して
   203  			// 必ず返されることが保証されています。
   204  			if _, err := io.ReadFull(zr, b[:1]); err != nil {
   205  				if err == io.EOF {
   206  					break // 送信者がストリームを閉じました
   207  				}
   208  				log.Fatal(err)
   209  			}
   210  
   211  			// メッセージの内容を読み取る。
   212  			n := int(b[0])
   213  			if _, err := io.ReadFull(zr, b[:n]); err != nil {
   214  				log.Fatal(err)
   215  			}
   216  
   217  			fmt.Printf("Received %d bytes: %s\n", n, b[:n])
   218  		}
   219  		fmt.Println()
   220  
   221  		if err := zr.Close(); err != nil {
   222  			log.Fatal(err)
   223  		}
   224  	}()
   225  
   226  	// Output:
   227  	// Received 1 bytes: A
   228  	// Received 4 bytes: long
   229  	// Received 4 bytes: time
   230  	// Received 3 bytes: ago
   231  	// Received 2 bytes: in
   232  	// Received 1 bytes: a
   233  	// Received 6 bytes: galaxy
   234  	// Received 4 bytes: far,
   235  	// Received 3 bytes: far
   236  	// Received 7 bytes: away...
   237  }