3

I have the following code that writes a text file in a zip:

FileOutputStream fOut = new FileOutputStream(fullFilename, false);
BufferedOutputStream bOut = new BufferedOutputStream(fOut);
ZipOutputStream zOut = new ZipOutputStream(bOut);

zOut.putNextEntry(new ZipEntry("aFile1.txt"));
//Do some processing and write to zOut...
zOut.write(...);
(...)
zOut.closeEntry();

zOut.close();
//Etc (close all resources)

I would need to change the filename of the zipEntry after it has been written (as its name will depend on its content written).

Also, it is not an option to write in a buffer and write to file only when final filename is known (because file size is potentially very large: not enough memory).

Any advice on how to do this would be greatly appreciated!

Thanks, Thomas

Tom
  • 1,375
  • 3
  • 24
  • 45

2 Answers2

3

It is a missing functionality, which could have been simple, as the entries themselves are not compressed.

The easiest way, requiring a rewrite though, is the zip FileSystem: since java 7 you may use a zip file as a virtual file system: writing, renaming and moving files in them. An example. You copy a file from the normal file system into the zip file system, and later rename the file in the zip.

// Create the zip file:
URI zipURI = URI.create("jar:file:" + fullFilename); // "jar:file:/.../... .zip"
Map<String, Object> env = new HashMap<>(); 
env.put("create", "true");
FileSystem zipFS = FileSystems.newFileSystem(zipURI, env, null);

// Write to aFile1.txt:
Path pathInZipfile = zipFS.getPath("/aFile1.txt");
BufferedWriter out = Files.newBufferedWriter(pathInZipfile,
        StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW);
out.write("Press any key, except both shift keys\n");
out.close();

// Rename file:
Path pathInZipfile2 = zipFS.getPath("/aFile2.txt");
Files.move(pathInZipfile, pathInZipfile2);

zipFS.close();

In principle you could also keep your old code - without renaming. And use a zip file system just for renaming.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • It isn't simple because the entry name forms part of the local file header, which has to be written to the output stream before the compressed data. I suppose if you had a seekable stream as the underlying destination you could conceivably go back and modify the header to change the name to another one but only if the new name is representable in exactly the same number of bytes as the old one... – Ian Roberts Jan 25 '14 at 00:17
  • @IanRoberts you bring it to the point: a missing random access seek and tell file position is missing in java's FileOutputStream. But the zip format is that simple, that one could make a list of modifiable zip entries using RandomAccessFile. – Joop Eggen Jan 25 '14 at 00:27
0

How about saving the contents of aFile1.txt to a temporary file on disk, renaming it, and then creating the zip file afterwards? The last step can then be deleting the file you created on disk.

Peter
  • 131
  • 1
  • 4