ZipFiles.java [src/csip/utils] Revision: Date:
/*
* $Id: 2.8+7 ZipFiles.java 7dfec32a5e62 2023-11-27 od $
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API and application suite.
*
* 2012-2022, Olaf David and others, OMSLab, Colorado State University.
*
* OMSLab licenses this file to you under the MIT license.
* See the LICENSE file in the project root for more information.
*/
package csip.utils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.WildcardFileFilter;
/**
* Basic (g)zip/(g)unzip operations.
*
* @author od
*/
public class ZipFiles {
private static final int BUF_SIZE = 4096;
private static final String ZIP_EXT = ".zip";
private static final String GZIP_EXT = ".gz";
/**
* gzip a file. a new file with the added extension '.gz' will be created.
*
* @param file The file to gzip
* @return the gzipped file
* @throws IOException if it fails
*/
public static File gzip(File file) throws IOException {
File out = new File(file.toString() + GZIP_EXT);
try (InputStream is = new BufferedInputStream(new FileInputStream(file)); GZIPOutputStream gzos = new GZIPOutputStream(new FileOutputStream(out), BUF_SIZE)) {
byte[] buf = new byte[BUF_SIZE];
int l;
while ((l = is.read(buf)) != -1) {
gzos.write(buf, 0, l);
}
}
return out;
}
/**
* gunzip a file.
*
* @param gzFile the file to gunzip, assumes a filename that has the .gz
* extension added.
* @return the gunzipped file
* @throws IOException if unzipping fails
*/
public static File gunzip(File gzFile) throws IOException {
String fname = gzFile.getName();
if (!fname.endsWith(GZIP_EXT))
throw new IllegalArgumentException("Illegal file name: " + gzFile);
File nf = new File(gzFile.getParentFile(), fname.substring(0, fname.length() - 3));
try (InputStream is = new GZIPInputStream(new FileInputStream(gzFile), BUF_SIZE); OutputStream fos = new BufferedOutputStream(new FileOutputStream(nf))) {
byte[] buf = new byte[BUF_SIZE];
int l;
while ((l = is.read(buf)) != -1) {
fos.write(buf, 0, l);
}
}
return nf;
}
/**
* Zip a directory.
*
* @param dir the directory to zip
* @return the zipped directory.
* @throws IOException if the operation fails
*/
public static File zip(File dir) throws IOException {
return zip(dir, new File(dir.getParentFile(), dir.getName() + ZIP_EXT));
}
/**
* Zips a dir into a file.
*
* @param dir the dir to zip
* @param zipFile the target zipfile
* @return the zipped file
* @throws IOException if something goes wrong
*/
public static File zip(File dir, File zipFile) throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
zos.setLevel(Deflater.BEST_COMPRESSION);
zip(dir, dir, zos, new byte[BUF_SIZE]);
}
return zipFile;
}
/**
* Zip a collection of files.
*
* @param zipFile the target zip file
* @param files the files to add
* @return the zip file
* @throws IOException if something goes wrong
*/
public static File zip(File zipFile, Collection<File> files) throws IOException {
return zip(zipFile, files.toArray(new Object[0]));
}
/**
* Zip an array of files.
*
* @param zipFile the target zip file
* @param files the files to put into the zip file, can be String, File or
* File[]
* @return the zip file
* @throws IOException if something goes wrong
*/
public static File zip(File zipFile, Object... files) throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
zos.setLevel(Deflater.BEST_COMPRESSION);
byte[] buf = new byte[BUF_SIZE];
for (Object file : files) {
File[] expfiles;
if (file instanceof File) {
File f = (File) file;
expfiles = resolve(f);
} else if (file instanceof File[]) {
expfiles = (File[]) file;
} else if (file instanceof String) {
File f = new File(file.toString());
expfiles = resolve(f);
} else {
throw new IllegalArgumentException("file: " + file.toString());
}
for (File expfile : expfiles) {
try (InputStream is = new BufferedInputStream(new FileInputStream(expfile))) {
ZipEntry ze = new ZipEntry(expfile.getName());
ze.setLastModifiedTime(FileTime.from(expfile.lastModified(),
TimeUnit.MILLISECONDS));
zos.putNextEntry(ze);
int len;
while ((len = is.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
}
}
}
}
return zipFile;
}
private static void zip(File dir, File base, ZipOutputStream zos, byte[] buf) throws IOException {
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
zip(file, base, zos, buf);
} else {
try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
ZipEntry ze = new ZipEntry(file.getPath().substring(base.getPath().length() + 1));
ze.setLastModifiedTime(FileTime.from(file.lastModified(),
TimeUnit.MILLISECONDS));
zos.putNextEntry(ze);
int l;
while ((l = is.read(buf)) != -1) {
zos.write(buf, 0, l);
}
zos.closeEntry();
}
}
}
}
/**
* Unzip a file.
*
* @param zip the file to unzip.
* @return the directory
* @throws IOException if operation fails
*/
public static File unzip(File zip) throws IOException {
return unzip(zip, zip.getParentFile());
}
/**
* Unzip a file.
*
* @param zip the file to unzip
* @param dir the directory.
* @return the directory
* @throws IOException if unzipping fails
*/
public static File unzip(File zip, File dir) throws IOException {
return unzip(zip, dir.getCanonicalPath() + "/");
}
public static File unzip(File zip, String dir) throws IOException {
byte[] buf = new byte[BUF_SIZE];
try (ZipFile archive = new ZipFile(zip)) {
Enumeration<? extends ZipEntry> e = archive.entries();
if (!dir.endsWith("/"))
throw new IOException("target directory not ending with '/'.");
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
File file = new File(dir, entry.getName());
if (!file.getCanonicalPath().startsWith(dir))
throw new IOException("Entry is outside of the target directory.");
// System.out.println(file.getCanonicalPath());
if (entry.isDirectory()) {
file.mkdirs();
continue;
}
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
try (InputStream is = archive.getInputStream(entry); OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
int l;
while ((l = is.read(buf)) != -1) {
out.write(buf, 0, l);
}
}
if (entry.getLastModifiedTime() != null)
file.setLastModified(entry.getLastModifiedTime().toMillis());
}
}
return new File(dir);
}
static boolean isWildcardPattern(String p) {
return p.contains("*") || p.contains("?");
}
static File[] resolve(File f) {
if (isWildcardPattern(f.getName())) {
FilenameFilter ff = new WildcardFileFilter(f.getName(), IOCase.INSENSITIVE);
return f.getParentFile().listFiles(ff);
} else {
return new File[]{f};
}
}
}