Zipping in Java

Java >= 7

Building Zip files was always easy in Java, but it was always also kind of awkward, and this is because one had to normally go through 3 steps, create the zip output stream, insert an entry and add the bytes for each entry. This is the kind of a weird sequence that leads several to feel that it is easy but it could be better. Liferay for instance uses an ancient library to build files in a easier process, which also works in a higher abstraction level.
In this post I will show you 3 approaches to build a zip file in Java (one from Liferay). The goal is to show how it used to be and how we can now operate in more abstract ways.


The old way


String sourceFile = "test.txt";
File file = new File( sourceFile );

try (
		ZipOutputStream zipOutputStream = new ZipOutputStream( new FileOutputStream( "archive.zip" ) );
		FileInputStream fileInputStream = new FileInputStream( file )
) {

	ZipEntry zipEntry = new ZipEntry( file.getName( ) );
	zipOutputStream.putNextEntry( zipEntry );

	final byte[] bytes = new byte[ 1024 ];
	int length;

	while ( ( length = fileInputStream.read( bytes ) ) >= 0 ) {
		zipOutputStream.write( bytes, 0, length );
	}

}

As mentioned, this is pretty simple, but it is also, well...


The Liferay way

When working with Liferay, you can see something that is way simpler and it is a good exemplification on what is not so good about the previous example.


ZipWriter zipWriter = getZipWriter( );

for ( Pair< String, File > entry : files ) {

	String fileName = entry.getKey( );
	File file = entry.getValue( );

	zipWriter.addEntry( fileName, new FileInputStream( file ) );
}

File archive = zipWriter.getFile( );

As we can see, when reading Liferay's source code we find what we would expect from a straightforward functionality like this. However, this code hides lots that the eyes cannot see. For instance, it uses extra dependencies, one of which is an ancient library that is not only deprecated and no longer maintained, its name and focus have changed several times along with the difficulty of finding its source. I am referring to the family of classes that comes from de.schlichtherle.io. 
Ok, the lib works but all links that are referring to it are either broken or advising to use a more recent one. This was my second red flag when debugging a problem coming from a simple use case: zip ODT files (not supported in the version that comes with Liferay 7.0).


The simple way

Java 7 brings a way simpler method to build archives while keeping the advantages of working in hiegher abstraction levels.


private FileSystem getZipFs( ) throws IOException {

   Map< String, String > env = new HashMap<>( );
   env.put( "create", "true" );
   env.put( "encoding", StandardCharsets.UTF_8.toString( ) );

   URI uri = URI.create( "jar:file:" + archivePath );
   return FileSystems.newFileSystem( uri, env );

}

And just like that you have a new file system to work with and even if you have lots of files to compress the code is still trivial, without needing extra dependencies. 


try ( FileSystem zipFs = getZipFs( ) ) {

   for ( Pair< String, File > entry : files ) {

      String fileName = entry.getKey( );
      File file = entry.getValue( );

      Path pathInZipFile = zipFs.getPath( fileName );
      Files.copy( file.toPath( ), pathInZipFile, StandardCopyOption.REPLACE_EXISTING );
   }

}

More Blog Entries

0 Comments