Tagged: zip
unzip in java
I thought I do know how to unzip in Java. Here is the code I used to think that is OK.
/** * Unzip given <code>source</code> zip file's contents into specified * <code>target</code> directory. * * @param source source zip file * @param target target directory * @throws IOException if an I/O error occurs. */ public static void unzip(final File source, final File target) throws IOException { if (source == null) { throw new NullPointerException("null source"); } if (!source.isFile()) { throw new IllegalArgumentException("source doesn't exist"); } if (target == null) { throw new NullPointerException("null target"); } if (!target.isDirectory()) { throw new IllegalArgumentException("target doesn't exist"); } final ZipInputStream sourceStream = new ZipInputStream(new FileInputStream(source)); try { final byte[] buffer = new byte[8192]; ZipEntry sourceEntry = null; while (true) { sourceEntry = sourceStream.getNextEntry(); if (sourceEntry == null) { break; } final File targetEntry = new File(target, sourceEntry.getName()); if (sourceEntry.isDirectory()) { if (!targetEntry.isDirectory() && !targetEntry.mkdirs()) { throw new IOException( "failed to create target directory: " + targetEntry.getPath()); } sourceStream.closeEntry(); continue; } final OutputStream targetStream = new FileOutputStream(targetEntry); try { int read = -1; while (true) { read = sourceStream.read(buffer); if (read == -1) { break; } targetStream.write(buffer, 0, read); } targetStream.flush(); } finally { targetStream.close(); } sourceStream.closeEntry(); } } finally { sourceStream.close(); } }
And I encountered the evil.zip file which has following entries.
file dir/ dir/file dir/dir/file
See that there is no entry named dir/dir/
between the 3rd and the 4th entry. This case make above method to throw a FileNotFoundException
that can’t open the file output stream for dir/dir/file
because of the absence of dir/dir/
directory.
I’m not sure about the actual validity of the zip file. (Somebody tell me.) So I decided to insert some code to check if those required directories are exist or not.
/** * Unzip given <code>source</code> zip file's contents into specified * <code>target</code> directory. * * @param source source zip file * @param target target directory * @throws IOException if an I/O error occurs. */ public static void unzip(final File source, final File target) throws IOException { if (source == null) { throw new NullPointerException("null source"); } if (!source.isFile()) { throw new IllegalArgumentException("source doesn't exist"); } if (target == null) { throw new NullPointerException("null target"); } if (!target.isDirectory()) { throw new IllegalArgumentException("target doesn't exist"); } final ZipInputStream sourceStream = new ZipInputStream(new FileInputStream(source)); try { final byte[] buffer = new byte[8192]; ZipEntry sourceEntry = null; while (true) { sourceEntry = sourceStream.getNextEntry(); if (sourceEntry == null) { break; } final File targetEntry = new File(target, sourceEntry.getName()); if (sourceEntry.isDirectory()) { if (!targetEntry.isDirectory() && !targetEntry.mkdirs()) { throw new IOException( "failed to create target directory: " + targetEntry.getPath()); } sourceStream.closeEntry(); continue; } final int index = sourceEntry.getName().lastIndexOf('/'); if (index != -1) { final File parent = new File( target, sourceEntry.getName().substring(0, index)); if (!parent.isDirectory() && !parent.mkdirs()) { throw new IOException( "failed to create a directory: " + parent.getPath()); } } final OutputStream targetStream = new FileOutputStream(targetEntry); try { int read = -1; while (true) { read = sourceStream.read(buffer); if (read == -1) { break; } targetStream.write(buffer, 0, read); } targetStream.flush(); } finally { targetStream.close(); } sourceStream.closeEntry(); } } finally { sourceStream.close(); } }
remove all entries denote for hidden files from a zip archive
$ zip -d zip.zip \\.* \*/\.[^/]*