View Javadoc

1   package com.atlassian.core.util.zip;
2   
3   import org.apache.commons.io.IOUtils;
4   import org.apache.commons.lang.StringUtils;
5   
6   import java.io.BufferedInputStream;
7   import java.io.File;
8   import java.io.FileInputStream;
9   import java.io.IOException;
10  import java.io.InputStream;
11  import java.util.zip.ZipEntry;
12  import java.util.zip.ZipOutputStream;
13  
14  /**
15   * Handles adding files to zip archives. Supports appending files to existing zip output stream.
16   *
17   * @since v4.6.13
18   */
19  public class FileArchiver
20  {
21      private final ZipOutputStream zipOutputStream;
22  
23      public FileArchiver(final ZipOutputStream zipOutputStream)
24      {
25          if (zipOutputStream == null)
26          {
27              throw new NullPointerException("output stream can't be null");
28          }
29          this.zipOutputStream = zipOutputStream;
30      }
31  
32      /**
33       * Adds file to the current archive output stream
34       *
35       * @param file file to add to archive
36       * @param archiveFolderToCreate name of topmost folder to create inside of the archive, leave blank to not create.
37       * @throws java.io.IOException if can't read from file or can't write to output
38       */
39      public void addToArchive(final File file, final String path, final String archiveFolderToCreate) throws IOException
40      {
41          if ((file == null) || !file.exists())
42          {
43              return;
44          }
45          final String escapedPath = getEntryPath(FilePathUtils.stripSlashes(path), archiveFolderToCreate);
46          final ZipEntry entry = new ZipEntry(escapedPath);
47  
48          entry.setTime(file.lastModified());
49          zipOutputStream.putNextEntry(entry);
50  
51          final InputStream in = new BufferedInputStream(new FileInputStream(file));
52          try
53          {
54              IOUtils.copyLarge(in, zipOutputStream);
55          }
56          finally
57          {
58              IOUtils.closeQuietly(in);
59          }
60  
61      }
62  
63      public void addDirectoryToArchive(final File file, final String path, final String archiveFolderName)
64              throws IOException
65      {
66          if ((file == null) || !file.exists() || !file.isDirectory())
67          {
68              return;
69          }
70          final String escapedPath = getEntryPath(FilePathUtils.stripSlashes(path), archiveFolderName);
71          final String directoryEscapedPath = escapedPath.endsWith("/") ? escapedPath : escapedPath + "/";
72  
73          final ZipEntry entry = new ZipEntry(directoryEscapedPath);
74  
75          entry.setTime(file.lastModified());
76          zipOutputStream.putNextEntry(entry);
77      }
78  
79      /**
80       * Builds a file path for an entry inside of the archive Replaces forward slashes, removes extra slashes. Also
81       * handles creation of a topmost directory in archive, if necessary.
82       *
83       * @param path related path inside of archive
84       * @param archiveFolderToCreate name of topmost folder to create inside of the archive, leave blank to not create.
85       * @return path to use inside of archive
86       */
87      private static String getEntryPath(final String path, final String archiveFolderToCreate)
88      {
89          // if creating zip on a windows system, convert all backslashes to forward slashes so that the resulting file is platform-independent (work on unix and windows)
90          String sanitisedPath = path;
91          sanitisedPath = sanitisedPath.replaceAll("\\\\", "/");
92  
93          // also drop the leading slash
94          if (sanitisedPath.length() > 0 && sanitisedPath.charAt(0) == '/')
95          {
96              sanitisedPath = sanitisedPath.substring(1);
97          }
98          if (StringUtils.isNotBlank(archiveFolderToCreate))
99          {
100             sanitisedPath = archiveFolderToCreate + "/" + path;
101         }
102         return sanitisedPath;
103     }
104 }