Black Lives Matter. Support the Equal Justice Initiative.

Source file src/compress/flate/example_test.go

Documentation: compress/flate

     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  	"bytes"
     9  	"compress/flate"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"os"
    14  	"strings"
    15  	"sync"
    16  )
    17  
    18  // In performance critical applications, Reset can be used to discard the
    19  // current compressor or decompressor state and reinitialize them quickly
    20  // by taking advantage of previously allocated memory.
    21  func Example_reset() {
    22  	proverbs := []string{
    23  		"Don't communicate by sharing memory, share memory by communicating.\n",
    24  		"Concurrency is not parallelism.\n",
    25  		"The bigger the interface, the weaker the abstraction.\n",
    26  		"Documentation is for users.\n",
    27  	}
    28  
    29  	var r strings.Reader
    30  	var b bytes.Buffer
    31  	buf := make([]byte, 32<<10)
    32  
    33  	zw, err := flate.NewWriter(nil, flate.DefaultCompression)
    34  	if err != nil {
    35  		log.Fatal(err)
    36  	}
    37  	zr := flate.NewReader(nil)
    38  
    39  	for _, s := range proverbs {
    40  		r.Reset(s)
    41  		b.Reset()
    42  
    43  		// Reset the compressor and encode from some input stream.
    44  		zw.Reset(&b)
    45  		if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
    46  			log.Fatal(err)
    47  		}
    48  		if err := zw.Close(); err != nil {
    49  			log.Fatal(err)
    50  		}
    51  
    52  		// Reset the decompressor and decode to some output stream.
    53  		if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
    54  			log.Fatal(err)
    55  		}
    56  		if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
    57  			log.Fatal(err)
    58  		}
    59  		if err := zr.Close(); err != nil {
    60  			log.Fatal(err)
    61  		}
    62  	}
    63  
    64  	// Output:
    65  	// Don't communicate by sharing memory, share memory by communicating.
    66  	// Concurrency is not parallelism.
    67  	// The bigger the interface, the weaker the abstraction.
    68  	// Documentation is for users.
    69  }
    70  
    71  // A preset dictionary can be used to improve the compression ratio.
    72  // The downside to using a dictionary is that the compressor and decompressor
    73  // must agree in advance what dictionary to use.
    74  func Example_dictionary() {
    75  	// The dictionary is a string of bytes. When compressing some input data,
    76  	// the compressor will attempt to substitute substrings with matches found
    77  	// in the dictionary. As such, the dictionary should only contain substrings
    78  	// that are expected to be found in the actual data stream.
    79  	const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
    80  
    81  	// The data to compress should (but is not required to) contain frequent
    82  	// substrings that match those in the dictionary.
    83  	const data = `<?xml version="1.0"?>
    84  <book>
    85  	<meta name="title" content="The Go Programming Language"/>
    86  	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
    87  	<meta name="published" content="2015-10-26"/>
    88  	<meta name="isbn" content="978-0134190440"/>
    89  	<data>...</data>
    90  </book>
    91  `
    92  
    93  	var b bytes.Buffer
    94  
    95  	// Compress the data using the specially crafted dictionary.
    96  	zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
    97  	if err != nil {
    98  		log.Fatal(err)
    99  	}
   100  	if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
   101  		log.Fatal(err)
   102  	}
   103  	if err := zw.Close(); err != nil {
   104  		log.Fatal(err)
   105  	}
   106  
   107  	// The decompressor must use the same dictionary as the compressor.
   108  	// Otherwise, the input may appear as corrupted.
   109  	fmt.Println("Decompressed output using the dictionary:")
   110  	zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
   111  	if _, err := io.Copy(os.Stdout, zr); err != nil {
   112  		log.Fatal(err)
   113  	}
   114  	if err := zr.Close(); err != nil {
   115  		log.Fatal(err)
   116  	}
   117  
   118  	fmt.Println()
   119  
   120  	// Substitute all of the bytes in the dictionary with a '#' to visually
   121  	// demonstrate the approximate effectiveness of using a preset dictionary.
   122  	fmt.Println("Substrings matched by the dictionary are marked with #:")
   123  	hashDict := []byte(dict)
   124  	for i := range hashDict {
   125  		hashDict[i] = '#'
   126  	}
   127  	zr = flate.NewReaderDict(&b, hashDict)
   128  	if _, err := io.Copy(os.Stdout, zr); err != nil {
   129  		log.Fatal(err)
   130  	}
   131  	if err := zr.Close(); err != nil {
   132  		log.Fatal(err)
   133  	}
   134  
   135  	// Output:
   136  	// Decompressed output using the dictionary:
   137  	// <?xml version="1.0"?>
   138  	// <book>
   139  	// 	<meta name="title" content="The Go Programming Language"/>
   140  	// 	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
   141  	// 	<meta name="published" content="2015-10-26"/>
   142  	// 	<meta name="isbn" content="978-0134190440"/>
   143  	// 	<data>...</data>
   144  	// </book>
   145  	//
   146  	// Substrings matched by the dictionary are marked with #:
   147  	// #####################
   148  	// ######
   149  	// 	############title###########The Go Programming Language"/#
   150  	// 	############authors###########Alan Donovan and Brian Kernighan"/#
   151  	// 	############published###########2015-10-26"/#
   152  	// 	############isbn###########978-0134190440"/#
   153  	// 	######...</#####
   154  	// </#####
   155  }
   156  
   157  // DEFLATE is suitable for transmitting compressed data across the network.
   158  func Example_synchronization() {
   159  	var wg sync.WaitGroup
   160  	defer wg.Wait()
   161  
   162  	// Use io.Pipe to simulate a network connection.
   163  	// A real network application should take care to properly close the
   164  	// underlying connection.
   165  	rp, wp := io.Pipe()
   166  
   167  	// Start a goroutine to act as the transmitter.
   168  	wg.Add(1)
   169  	go func() {
   170  		defer wg.Done()
   171  
   172  		zw, err := flate.NewWriter(wp, flate.BestSpeed)
   173  		if err != nil {
   174  			log.Fatal(err)
   175  		}
   176  
   177  		b := make([]byte, 256)
   178  		for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
   179  			// We use a simple framing format where the first byte is the
   180  			// message length, followed the message itself.
   181  			b[0] = uint8(copy(b[1:], m))
   182  
   183  			if _, err := zw.Write(b[:1+len(m)]); err != nil {
   184  				log.Fatal(err)
   185  			}
   186  
   187  			// Flush ensures that the receiver can read all data sent so far.
   188  			if err := zw.Flush(); err != nil {
   189  				log.Fatal(err)
   190  			}
   191  		}
   192  
   193  		if err := zw.Close(); err != nil {
   194  			log.Fatal(err)
   195  		}
   196  	}()
   197  
   198  	// Start a goroutine to act as the receiver.
   199  	wg.Add(1)
   200  	go func() {
   201  		defer wg.Done()
   202  
   203  		zr := flate.NewReader(rp)
   204  
   205  		b := make([]byte, 256)
   206  		for {
   207  			// Read the message length.
   208  			// This is guaranteed to return for every corresponding
   209  			// Flush and Close on the transmitter side.
   210  			if _, err := io.ReadFull(zr, b[:1]); err != nil {
   211  				if err == io.EOF {
   212  					break // The transmitter closed the stream
   213  				}
   214  				log.Fatal(err)
   215  			}
   216  
   217  			// Read the message content.
   218  			n := int(b[0])
   219  			if _, err := io.ReadFull(zr, b[:n]); err != nil {
   220  				log.Fatal(err)
   221  			}
   222  
   223  			fmt.Printf("Received %d bytes: %s\n", n, b[:n])
   224  		}
   225  		fmt.Println()
   226  
   227  		if err := zr.Close(); err != nil {
   228  			log.Fatal(err)
   229  		}
   230  	}()
   231  
   232  	// Output:
   233  	// Received 1 bytes: A
   234  	// Received 4 bytes: long
   235  	// Received 4 bytes: time
   236  	// Received 3 bytes: ago
   237  	// Received 2 bytes: in
   238  	// Received 1 bytes: a
   239  	// Received 6 bytes: galaxy
   240  	// Received 4 bytes: far,
   241  	// Received 3 bytes: far
   242  	// Received 7 bytes: away...
   243  }
   244  

View as plain text