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 }