title: Golang archive/zip producing corrupt zip files
body: <p>I wrote a small utility in Go to zip a folder. It seems to work in many cases, but every now and then it produces a zip file that is coming up as corrupt when I open it in an unzip app (they all seem to complain about it).</p>
  
  <p>Here is the code:</p>
  
  <pre><code>const (
      singleFileByteLimit = 107374182400 // 1 GB
      chunkSize           = 1024         // 1 KB
  )
  
  // ZipFolder zips the given folder to the a zip file
  // with the given name
  func ZipFolder(srcFolder string, destFile string) error {
      z := &amp;zipper{
          srcFolder: srcFolder,
          destFile:  destFile,
      }
      return z.zipFolder()
  }
  
  // We need a struct internally because the filepath WalkFunc
  // doesn't allow custom params. So we save them here so it can
  // access them
  type zipper struct {
      srcFolder string
      destFile  string
      writer    *zip.Writer
  }
  
  // internal function to zip a folder
  func (z *zipper) zipFolder() error {
      // create zip file
      zipFile, err := os.Create(z.destFile)
      if err != nil {
          return err
      }
      defer zipFile.Close()
  
      // create zip writer
      z.writer = zip.NewWriter(zipFile)
  
      // traverse the source folder
      err = filepath.Walk(z.srcFolder, z.zipFile)
      if err != nil {
          return nil
      }
  
      // close the zip file
      err = z.writer.Close()
      if err != nil {
          return err
      }
      return nil
  }
  
  // internal function to zip a file, called by filepath.Walk on each file
  func (z *zipper) zipFile(path string, f os.FileInfo, err error) error {
      // only zip files (directories are created by the files inside of them)
      // TODO allow creating folder when no files are inside
      if !f.IsDir() &amp;&amp; f.Size() &gt; 0 {
          // open file
          file, err := os.Open(path)
          if err != nil {
              return err
          }
          defer file.Close()
  
          // create new file in zip
          fileName := strings.TrimPrefix(path, z.srcFolder+"/")
          w, err := z.writer.Create(fileName)
          if err != nil {
              return err
          }
  
          // copy contents of the file to the zip writer
          err = copyContents(file, w)
          if err != nil {
              return err
          }
      }
  
      return nil
  }
  
  func copyContents(r io.Reader, w io.Writer) error {
      var size int64
      for {
          b := make([]byte, chunkSize)
  
          // we limit the size to avoid zip bombs
          size += chunkSize
          if size &gt; singleFileByteLimit {
              return errors.New("file too large, please contact us for assitance")
          }
  
          // read chunk into memory
          length, err := r.Read(b)
          if err == io.EOF {
              break
          } else if err != nil {
              return err
          }
          // write chunk to zip file
          _, err = w.Write(b[:length])
          if err != nil {
              return err
          }
      }
      return nil
  }
  </code></pre>