...

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