View Javadoc
1   package org.djutils.io;
2   
3   import java.io.BufferedWriter;
4   import java.io.File;
5   import java.io.FileNotFoundException;
6   import java.io.FileOutputStream;
7   import java.io.FileWriter;
8   import java.io.IOException;
9   import java.io.OutputStreamWriter;
10  import java.util.zip.ZipEntry;
11  import java.util.zip.ZipOutputStream;
12  
13  /**
14   * File writer for multiple files in to a zip file. Typical use is:
15   * 
16   * <pre>
17   * try (CompressedFileWriter compressedFileWriter = new CompressedFileWriter("CsvData.zip"))
18   * {
19   *     BufferedWriter bufferedWriter = compressedFileWriter.next("data_2023.csv");
20   *     
21   *     // write data for data_2023
22   *     bufferedWriter.write(...);
23   *     
24   *     compressedFileWriter.next("data_2024.csv");
25   *     
26   *     // write data for data_2024
27   *     bufferedWriter.write(...);
28   * }
29   * </pre>
30   * 
31   * If the {@code BufferedWriter} is closed, so too is the {@code CompressedFileWriter}. Any consumers of the
32   * {@code BufferedWriter} should thus not close it.
33   * <p>
34   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
35   * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
36   * </p>
37   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
38   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
39   * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
40   */
41  public final class CompressedFileWriter implements AutoCloseable
42  {
43  
44      /** Zip output stream to create new zip entries. */
45      private final ZipOutputStream zipOutputStream;
46  
47      /** Buffered writer to write in to. */
48      private BufferedWriter bufferedWriter;
49  
50      /**
51       * Constructor.
52       * @param file String; file, if this does not end with .zip (case insensitive), ".zip" will be appended to it
53       * @throws FileNotFoundException if the zip file can not be written
54       */
55      public CompressedFileWriter(final String file) throws FileNotFoundException
56      {
57          this.zipOutputStream =
58                  new ZipOutputStream(new FileOutputStream(file.toLowerCase().endsWith(".zip") ? file : file + ".zip"));
59          this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(this.zipOutputStream));
60      }
61  
62      /**
63       * Closes the previous file in the zip file, and opens up the next file. The {@code BufferedWriter} returned is the same for
64       * each call on a {@code CompressedFileWriter}.
65       * @param name String; name of the next file in the zip file
66       * @return BufferedWriter; writer to write the next file in to.
67       * @throws IOException if no next entry could be created in the zip file
68       */
69      public BufferedWriter next(final String name) throws IOException
70      {
71          this.bufferedWriter.flush();
72          this.zipOutputStream.putNextEntry(new ZipEntry(name));
73          return this.bufferedWriter;
74      }
75  
76      @Override
77      public void close() throws IOException
78      {
79          this.bufferedWriter.flush();
80          this.zipOutputStream.close();
81      }
82  
83      /**
84       * Creates a writer to write data to a file, which can be a zipped file or a regular file. In particular if
85       * {@code zipped = true}, then with {@code file = "myFile.csv"}, a file {@code myFile.csv.zip} will be created in which a
86       * file {@code myFile.csv} is located. Writing occurs on this file.
87       * @param filePath String; path of the file to write; in case of a zipped file, the filename of the zip-file will end with
88       *            .zip, and the filename in the zip file will be the the filename without .zip.
89       * @param zipped boolean; whether to contain the file in a zip file
90       * @return BufferedWriter writer tot write in to
91       * @throws IOException on error with filenames, file writing, closing, etc.
92       */
93      public static BufferedWriter create(final String filePath, final boolean zipped) throws IOException
94      {
95          if (zipped)
96          {
97              ZipOutputStream zipOutputStream = new ZipOutputStream(
98                      new FileOutputStream(filePath.toLowerCase().endsWith(".zip") ? filePath : filePath + ".zip"));
99              String fileName = new File(filePath).getName();
100             fileName = fileName.toLowerCase().endsWith(".zip") ? fileName.substring(0, fileName.length() - 4) : fileName;
101             zipOutputStream.putNextEntry(new ZipEntry(fileName));
102             return new BufferedWriter(new OutputStreamWriter(zipOutputStream));
103         }
104         return new BufferedWriter(new FileWriter(filePath));
105     }
106 
107 }