/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.toolbox; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; import java.util.Enumeration; import java.util.regex.Pattern; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.apache.commons.io.IOUtils; import org.openflexo.localization.FlexoLocalization; public class ZipUtils { public static final String VALID_ENTRY_NAME_REGEXP = "\\p{ASCII}+"; public static final Pattern VALID_ENTRY_NAME_PATTERN = Pattern.compile(VALID_ENTRY_NAME_REGEXP); private static final void copyInputStream(InputStream in, OutputStream out) throws IOException { try { byte[] buffer = new byte[4096]; int len; while ((len = in.read(buffer)) >= 0) { out.write(buffer, 0, len); } } finally { IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); } } public static final void unzip(File zip, File outputDir) throws ZipException, IOException { unzip(zip, outputDir, null); } public static final void unzip(File zip, File outputDir, IProgress progress) throws ZipException, IOException { Enumeration<? extends ZipEntry> entries; outputDir = outputDir.getCanonicalFile(); if (!outputDir.exists()) { boolean b = outputDir.mkdirs(); if (!b) { throw new IllegalArgumentException("Could not create dir " + outputDir.getAbsolutePath()); } } if (!outputDir.isDirectory()) { throw new IllegalArgumentException(outputDir.getAbsolutePath() + "is not a directory or is not writeable!"); } ZipFile zipFile; zipFile = new ZipFile(zip); entries = zipFile.entries(); if (progress != null) { progress.resetSecondaryProgress(zipFile.size()); } while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (progress != null) { progress.setSecondaryProgress(FlexoLocalization.localizedForKey("unzipping") + " " + entry.getName()); } if (entry.getName().startsWith("__MACOSX")) { continue; } if (entry.isDirectory()) { // Assume directories are stored parents first then // children. // This is not robust, just for demonstration purposes. new File(outputDir, entry.getName().replace('\\', '/')).mkdirs(); continue; } File outputFile = new File(outputDir, entry.getName().replace('\\', '/')); if (outputFile.getName().startsWith("._")) { // This block is made to drop MacOS crap added to zip files if (zipFile.getEntry(entry.getName().substring(0, entry.getName().length() - outputFile.getName().length()) + outputFile.getName().substring(2)) != null) { continue; } if (new File(outputFile.getParentFile(), outputFile.getName().substring(2)).exists()) { continue; } } FileUtils.createNewFile(outputFile); InputStream zipStream = null; FileOutputStream fos = null; try { zipStream = zipFile.getInputStream(entry); if (zipStream == null) { System.err.println("Could not find input stream for entry: " + entry.getName()); continue; } fos = new FileOutputStream(outputFile); copyInputStream(zipStream, new BufferedOutputStream(fos)); } catch (IOException e) { e.printStackTrace(); System.err.println("Could not extract: " + outputFile.getAbsolutePath() + " maybe some files contains invalid characters."); } finally { IOUtils.closeQuietly(zipStream); IOUtils.closeQuietly(fos); } } Collection<File> listFiles = org.apache.commons.io.FileUtils.listFiles(outputDir, null, true); for (File file : listFiles) { if (file.isFile() && file.getName().startsWith("._")) { File f = new File(file.getParentFile(), file.getName().substring(2)); if (f.exists()) { file.delete(); } } } zipFile.close(); } public static void unzip(File zip, String outputDirPath, IProgress progress) throws ZipException, IOException { File outputDir = new File(outputDirPath); unzip(zip, outputDir, progress); } public static void unzip(File zip, String outputDirPath) throws ZipException, IOException { unzip(zip, outputDirPath, null); } /** * This method makes a zip file on file <code>zipOutput</code>out of the given <code>fileToZip</code> * * @param zipOutput * - the output where to write the zip * @param fileToZip * the file to zip (wheter it is a file or a directory) * @throws IOException */ public static void makeZip(File zipOutput, File fileToZip) throws IOException { makeZip(zipOutput, fileToZip, null); } /** * This method makes a zip file on file <code>zipOutput</code>out of the given <code>fileToZip</code> * * @param zipOutput * - the output where to write the zip * @param fileToZip * the file to zip (wheter it is a file or a directory) * @throws IOException */ public static void makeZip(File zipOutput, File fileToZip, IProgress progress) throws IOException { makeZip(zipOutput, fileToZip, progress, null); } /** * This method makes a zip file on file <code>zipOutput</code>out of the given <code>fileToZip</code> * * @param zipOutput * - the output where to write the zip * @param fileToZip * the file to zip (wheter it is a file or a directory) * @throws IOException */ public static void makeZip(File zipOutput, File fileToZip, IProgress progress, FileFilter filter) throws IOException { makeZip(zipOutput, fileToZip, progress, filter, Deflater.DEFAULT_COMPRESSION); } public static void makeZip(File zipOutput, File fileToZip, IProgress progress, FileFilter filter, int level) throws IOException { FileUtils.createNewFile(zipOutput); ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipOutput)); zos.setLevel(level); try { if (fileToZip.isDirectory()) { if (progress != null) { progress.resetSecondaryProgress(FileUtils.countFilesInDirectory(fileToZip, true) + 1); } zipDir(fileToZip.getParentFile().getAbsolutePath().length() + 1, fileToZip, zos, progress, filter); } else { zipFile(fileToZip, zos, progress); } } finally { zos.close(); } } /** * This method makes a zip on the outputsream <code>zos</code>out of the given <code>dirToZip</code> * * @param dirToZip * the directory to zip * @param zos * the output stream where to write the zip data * @throws IOException */ public static void zipDir(File dirToZip, ZipOutputStream zos) throws IOException { zipDir(dirToZip, zos, null); } /** * This method makes a zip on the outputsream <code>zos</code>out of the given <code>dirToZip</code> * * @param dirToZip * the directory to zip * @param zos * the output stream where to write the zip data * @throws IOException */ public static void zipDir(File dirToZip, ZipOutputStream zos, IProgress progress) throws IOException { if (progress != null) { progress.resetSecondaryProgress(FileUtils.countFilesInDirectory(dirToZip, true)); } zipDir(dirToZip.getParentFile().getAbsolutePath().length() + 1, dirToZip, zos, progress, null); } /** * This method makes a zip on the outputsream <code>zos</code>out of the given <code>fileToZip</code> * * @param fileToZip * the file to zip * @param zos * the output stream where to write the zip data * @throws IOException */ public static void zipFile(File fileToZip, ZipOutputStream zos) throws IOException { zipFile(fileToZip, zos, null); } /** * This method makes a zip on the outputsream <code>zos</code>out of the given <code>fileToZip</code> * * @param fileToZip * the file to zip * @param zos * the output stream where to write the zip data * @throws IOException */ public static void zipFile(File fileToZip, ZipOutputStream zos, IProgress progress) throws IOException { if (progress != null) { progress.resetSecondaryProgress(1); } zipFile(fileToZip.getParentFile().getAbsolutePath().length() + 1, fileToZip, zos, progress); } public static void zipDir(int pathPrefixSize, File dirToZip, ZipOutputStream zos, IProgress progress, FileFilter filter) throws IOException { String[] dirList = dirToZip.list(); for (int i = 0; i < dirList.length; i++) { File f = new File(dirToZip, dirList[i]); if (filter == null || f != null && filter.accept(f)) { if (f.isDirectory()) { zipDir(pathPrefixSize, f, zos, progress, filter); } else { zipFile(pathPrefixSize, f, zos, progress); } } } } private static void zipFile(int pathPrefixSize, File fileToZip, ZipOutputStream zos, IProgress progress) throws IOException { if (!fileToZip.exists()) { return; } byte[] readBuffer = new byte[4096]; int bytesIn = 0; if (progress != null) { progress.setSecondaryProgress(FlexoLocalization.localizedForKey("zipping_file") + " " + fileToZip.getAbsolutePath().substring(pathPrefixSize)); } FileInputStream fis = new FileInputStream(fileToZip); try { ZipEntry anEntry = new ZipEntry(fileToZip.getAbsolutePath().substring(pathPrefixSize).replace('\\', '/')); // place the zip entry in the ZipOutputStream object zos.putNextEntry(anEntry); // now write the content of the file to the ZipOutputStream while ((bytesIn = fis.read(readBuffer)) != -1) { zos.write(readBuffer, 0, bytesIn); } } finally { fis.close(); } } public static void createEmptyZip(File zip) throws IOException { ZipOutputStream zos = null; try { FileUtils.createNewFile(zip); zos = new ZipOutputStream(new FileOutputStream(zip)); ZipEntry entry = new ZipEntry(""); zos.putNextEntry(entry); } finally { if (zos != null) { zos.close(); } } } public static void main(String[] args) { try { File zip = new File("d:/Work/SNA_1LS_REPAIR_VOICE_1_0_RO.zip"); File tmp = new File("D:/tmp/TestUnzip"); tmp.mkdirs(); unzip(zip, tmp); } catch (IOException e) { e.printStackTrace(); } } }