github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/archive/tar/example_test.go (about) 1 // Copyright 2013 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 tar_test 6 7 import ( 8 "archive/tar" 9 "bytes" 10 "crypto/md5" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "log" 15 "os" 16 "strings" 17 ) 18 19 func Example_minimal() { 20 // Create and add some files to the archive. 21 var buf bytes.Buffer 22 tw := tar.NewWriter(&buf) 23 var files = []struct { 24 Name, Body string 25 }{ 26 {"readme.txt", "This archive contains some text files."}, 27 {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"}, 28 {"todo.txt", "Get animal handling license."}, 29 } 30 for _, file := range files { 31 hdr := &tar.Header{ 32 Name: file.Name, 33 Mode: 0600, 34 Size: int64(len(file.Body)), 35 } 36 if err := tw.WriteHeader(hdr); err != nil { 37 log.Fatal(err) 38 } 39 if _, err := tw.Write([]byte(file.Body)); err != nil { 40 log.Fatal(err) 41 } 42 } 43 if err := tw.Close(); err != nil { 44 log.Fatal(err) 45 } 46 47 // Open and iterate through the files in the archive. 48 tr := tar.NewReader(&buf) 49 for { 50 hdr, err := tr.Next() 51 if err == io.EOF { 52 break // End of archive 53 } 54 if err != nil { 55 log.Fatal(err) 56 } 57 fmt.Printf("Contents of %s:\n", hdr.Name) 58 if _, err := io.Copy(os.Stdout, tr); err != nil { 59 log.Fatal(err) 60 } 61 fmt.Println() 62 } 63 64 // Output: 65 // Contents of readme.txt: 66 // This archive contains some text files. 67 // Contents of gopher.txt: 68 // Gopher names: 69 // George 70 // Geoffrey 71 // Gonzo 72 // Contents of todo.txt: 73 // Get animal handling license. 74 } 75 76 // A sparse file can efficiently represent a large file that is mostly empty. 77 // When packing an archive, Header.DetectSparseHoles can be used to populate 78 // the sparse map, while Header.PunchSparseHoles can be used to create a 79 // sparse file on disk when extracting an archive. 80 func Example_sparseAutomatic() { 81 // Create the source sparse file. 82 src, err := ioutil.TempFile("", "sparse.db") 83 if err != nil { 84 log.Fatal(err) 85 } 86 defer os.Remove(src.Name()) // Best-effort cleanup 87 defer func() { 88 if err := src.Close(); err != nil { 89 log.Fatal(err) 90 } 91 }() 92 if err := src.Truncate(10e6); err != nil { 93 log.Fatal(err) 94 } 95 for i := 0; i < 10; i++ { 96 if _, err := src.Seek(1e6-1e3, io.SeekCurrent); err != nil { 97 log.Fatal(err) 98 } 99 if _, err := src.Write(bytes.Repeat([]byte{'0' + byte(i)}, 1e3)); err != nil { 100 log.Fatal(err) 101 } 102 } 103 104 // Create an archive and pack the source sparse file to it. 105 var buf bytes.Buffer 106 tw := tar.NewWriter(&buf) 107 fi, err := src.Stat() 108 if err != nil { 109 log.Fatal(err) 110 } 111 hdr, err := tar.FileInfoHeader(fi, "") 112 if err != nil { 113 log.Fatal(err) 114 } 115 if err := hdr.DetectSparseHoles(src); err != nil { 116 log.Fatal(err) 117 } 118 if err := tw.WriteHeader(hdr); err != nil { 119 log.Fatal(err) 120 } 121 if _, err := io.Copy(tw, src); err != nil { 122 log.Fatal(err) 123 } 124 if err := tw.Close(); err != nil { 125 log.Fatal(err) 126 } 127 128 // Create the destination sparse file. 129 dst, err := ioutil.TempFile("", "sparse.db") 130 if err != nil { 131 log.Fatal(err) 132 } 133 defer os.Remove(dst.Name()) // Best-effort cleanup 134 defer func() { 135 if err := dst.Close(); err != nil { 136 log.Fatal(err) 137 } 138 }() 139 140 // Open the archive and extract the sparse file into the destination file. 141 tr := tar.NewReader(&buf) 142 hdr, err = tr.Next() 143 if err != nil { 144 log.Fatal(err) 145 } 146 if err := hdr.PunchSparseHoles(dst); err != nil { 147 log.Fatal(err) 148 } 149 if _, err := io.Copy(dst, tr); err != nil { 150 log.Fatal(err) 151 } 152 153 // Verify that the sparse files are identical. 154 want, err := ioutil.ReadFile(src.Name()) 155 if err != nil { 156 log.Fatal(err) 157 } 158 got, err := ioutil.ReadFile(dst.Name()) 159 if err != nil { 160 log.Fatal(err) 161 } 162 fmt.Printf("Src MD5: %08x\n", md5.Sum(want)) 163 fmt.Printf("Dst MD5: %08x\n", md5.Sum(got)) 164 165 // Output: 166 // Src MD5: 33820d648d42cb3da2515da229149f74 167 // Dst MD5: 33820d648d42cb3da2515da229149f74 168 } 169 170 // The SparseHoles can be manually constructed without Header.DetectSparseHoles. 171 func Example_sparseManual() { 172 // Define a sparse file to add to the archive. 173 // This sparse files contains 5 data fragments, and 4 hole fragments. 174 // The logical size of the file is 16 KiB, while the physical size of the 175 // file is only 3 KiB (not counting the header data). 176 hdr := &tar.Header{ 177 Name: "sparse.db", 178 Size: 16384, 179 SparseHoles: []tar.SparseEntry{ 180 // Data fragment at 0..1023 181 {Offset: 1024, Length: 1024 - 512}, // Hole fragment at 1024..1535 182 // Data fragment at 1536..2047 183 {Offset: 2048, Length: 2048 - 512}, // Hole fragment at 2048..3583 184 // Data fragment at 3584..4095 185 {Offset: 4096, Length: 4096 - 512}, // Hole fragment at 4096..7679 186 // Data fragment at 7680..8191 187 {Offset: 8192, Length: 8192 - 512}, // Hole fragment at 8192..15871 188 // Data fragment at 15872..16383 189 }, 190 } 191 192 // The regions marked as a sparse hole are filled with NUL-bytes. 193 // The total length of the body content must match the specified Size field. 194 body := "" + 195 strings.Repeat("A", 1024) + 196 strings.Repeat("\x00", 1024-512) + 197 strings.Repeat("B", 512) + 198 strings.Repeat("\x00", 2048-512) + 199 strings.Repeat("C", 512) + 200 strings.Repeat("\x00", 4096-512) + 201 strings.Repeat("D", 512) + 202 strings.Repeat("\x00", 8192-512) + 203 strings.Repeat("E", 512) 204 205 h := md5.Sum([]byte(body)) 206 fmt.Printf("Write content of %s, Size: %d, MD5: %08x\n", hdr.Name, len(body), h) 207 fmt.Printf("Write SparseHoles of %s:\n\t%v\n\n", hdr.Name, hdr.SparseHoles) 208 209 // Create a new archive and write the sparse file. 210 var buf bytes.Buffer 211 tw := tar.NewWriter(&buf) 212 if err := tw.WriteHeader(hdr); err != nil { 213 log.Fatal(err) 214 } 215 if _, err := tw.Write([]byte(body)); err != nil { 216 log.Fatal(err) 217 } 218 if err := tw.Close(); err != nil { 219 log.Fatal(err) 220 } 221 222 // Open and iterate through the files in the archive. 223 tr := tar.NewReader(&buf) 224 for { 225 hdr, err := tr.Next() 226 if err == io.EOF { 227 break 228 } 229 if err != nil { 230 log.Fatal(err) 231 } 232 body, err := ioutil.ReadAll(tr) 233 if err != nil { 234 log.Fatal(err) 235 } 236 237 h := md5.Sum([]byte(body)) 238 fmt.Printf("Read content of %s, Size: %d, MD5: %08x\n", hdr.Name, len(body), h) 239 fmt.Printf("Read SparseHoles of %s:\n\t%v\n\n", hdr.Name, hdr.SparseHoles) 240 } 241 242 // Output: 243 // Write content of sparse.db, Size: 16384, MD5: 9b4e2cfae0f9303d30237718e891e9f9 244 // Write SparseHoles of sparse.db: 245 // [{1024 512} {2048 1536} {4096 3584} {8192 7680}] 246 // 247 // Read content of sparse.db, Size: 16384, MD5: 9b4e2cfae0f9303d30237718e891e9f9 248 // Read SparseHoles of sparse.db: 249 // [{1024 512} {2048 1536} {4096 3584} {8192 7680} {16384 0}] 250 }