package com.compomics.util.io.compression;
import com.compomics.util.waiting.WaitingHandler;
import java.io.*;
import java.util.HashSet;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
/**
* This class contains convenience methods for taring files.
*
* @author Marc Vaudel
*/
public class TarUtils {
/**
* Tar a given folder to a file.
*
* @param folder the original folder to tar
* @param destinationFile the destination file
* @param waitingHandler a waiting handler used to cancel the process (can
* be null)
* @throws FileNotFoundException exception thrown whenever a file is not
* found
* @throws ArchiveException exception thrown whenever an error occurred
* while taring
* @throws IOException exception thrown whenever an error occurred while
* reading/writing files
*/
public static void tarFolder(File folder, File destinationFile, WaitingHandler waitingHandler) throws FileNotFoundException, ArchiveException, IOException {
FileOutputStream fos = new FileOutputStream(destinationFile);
try {
BufferedOutputStream bos = new BufferedOutputStream(fos);
try {
TarArchiveOutputStream tarOutput = (TarArchiveOutputStream) new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.TAR, bos);
try {
tarOutput.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
File matchFolder = folder;
addFolderContent(tarOutput, matchFolder, waitingHandler);
} finally {
tarOutput.close();
}
} finally {
bos.close();
}
} finally {
fos.close();
}
}
/**
* Tar the content of a given folder to a file.
*
* @param folder the original folder to tar
* @param destinationFile the destination file
* @param exceptionsPaths a list of paths to files or folders which should be excluded from taring
* @param waitingHandler a waiting handler used to cancel the process (can
* be null)
* @throws FileNotFoundException exception thrown whenever a file is not
* found
* @throws ArchiveException exception thrown whenever an error occurred
* while taring
* @throws IOException exception thrown whenever an error occurred while
* reading/writing files
*/
public static void tarFolderContent(File folder, File destinationFile, HashSet<String> exceptionsPaths, WaitingHandler waitingHandler) throws FileNotFoundException, ArchiveException, IOException {
FileOutputStream fos = new FileOutputStream(destinationFile);
try {
BufferedOutputStream bos = new BufferedOutputStream(fos);
try {
TarArchiveOutputStream tarOutput = (TarArchiveOutputStream) new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.TAR, bos);
try {
tarOutput.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
for (File file : folder.listFiles()) {
String path = file.getAbsolutePath();
if (!exceptionsPaths.contains(path)) {
if (file.isDirectory()) {
addFolderContent(tarOutput, file, waitingHandler);
} else {
addFile(tarOutput, file, waitingHandler);
}
}
}
} finally {
tarOutput.close();
}
} finally {
bos.close();
}
} finally {
fos.close();
}
}
/**
* Add content to the tar file.
*
* @param tarOutput the archive output stream
* @param folder the folder to add
* @param waitingHandler a waiting handler used to cancel the process (can
* be null)
* @throws FileNotFoundException exception thrown whenever a file is not
* found
* @throws IOException exception thrown whenever an error occurred while
* reading/writing files
*/
public static void addFolderContent(ArchiveOutputStream tarOutput, File folder, WaitingHandler waitingHandler) throws FileNotFoundException, IOException {
addFolderContent(tarOutput, folder, null, waitingHandler);
}
/**
* Add content to the tar file.
*
* @param tarOutput the archive output stream
* @param folder the folder to add
* @param parentFolder the parent folder to remove from the folder path
* @param waitingHandler a waiting handler used to cancel the process (can
* be null)
*
* @throws FileNotFoundException exception thrown whenever a file is not
* found
* @throws IOException exception thrown whenever an error occurred while
* reading/writing files
*/
private static void addFolderContent(ArchiveOutputStream tarOutput, File folder, String parentFolder, WaitingHandler waitingHandler) throws FileNotFoundException, IOException {
if (parentFolder == null) {
parentFolder = folder.getParentFile().getAbsolutePath();
}
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
addFolderContent(tarOutput, file, parentFolder, waitingHandler);
} else {
addFile(tarOutput, file, parentFolder, waitingHandler);
}
}
}
/**
* Add content to the tar file.
*
* @param tarOutput the archive output stream
* @param file the file to add
* @param waitingHandler a waiting handler used to cancel the process (can
* be null)
*
* @throws FileNotFoundException exception thrown whenever a file is not
* found
* @throws IOException exception thrown whenever an error occurred while
* reading/writing files
*/
private static void addFile(ArchiveOutputStream tarOutput, File file, WaitingHandler waitingHandler) throws FileNotFoundException, IOException {
addFile(tarOutput, file, null, waitingHandler);
}
/**
* Add content to the tar file.
*
* @param tarOutput the archive output stream
* @param file the file to add
* @param parentFolder the parent folder to remove from the folder path
* @param waitingHandler a waiting handler used to cancel the process (can
* be null)
*
* @throws FileNotFoundException exception thrown whenever a file is not
* found
* @throws IOException exception thrown whenever an error occurred while
* reading/writing files
*/
private static void addFile(ArchiveOutputStream tarOutput, File file, String parentFolder, WaitingHandler waitingHandler) throws FileNotFoundException, IOException {
if (parentFolder == null) {
parentFolder = file.getParentFile().getAbsolutePath();
}
final int BUFFER = 2048;
FileInputStream fi = new FileInputStream(file);
try {
BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
try {
byte data[] = new byte[BUFFER];
String filePath = file.getAbsolutePath();
String relativePath = filePath.substring(parentFolder.length() + 1);
TarArchiveEntry entry = new TarArchiveEntry(file, relativePath);
tarOutput.putArchiveEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER)) != -1) {
if (waitingHandler != null && waitingHandler.isRunCanceled()) {
break;
}
tarOutput.write(data, 0, count);
}
tarOutput.closeArchiveEntry();
} finally {
origin.close();
}
} finally {
fi.close();
}
}
/**
* Extracts files from a tar.
*
* @param tarFile the tar file
* @param waitingHandler a waiting handler displaying progress and allowing
* canceling the process
*
* @throws FileNotFoundException if a FileNotFoundException occurs
* @throws ArchiveException if an ArchiveException occurs
* @throws IOException if an IOException occurs
*/
public static void extractFile(File tarFile, WaitingHandler waitingHandler) throws FileNotFoundException, ArchiveException, IOException {
extractFile(tarFile, null, waitingHandler);
}
/**
* Extracts files from a tar.
*
* @param tarFile the tar file
* @param destinationFolder the destination folder, if null the file will be
* extracted according to the archive name
* @param waitingHandler a waiting handler displaying progress and allowing
* canceling the process
*
* @throws FileNotFoundException if a FileNotFoundException occurs
* @throws ArchiveException if an ArchiveException occurs
* @throws IOException if an IOException occurs
*/
public static void extractFile(File tarFile, File destinationFolder, WaitingHandler waitingHandler) throws FileNotFoundException, ArchiveException, IOException {
final int BUFFER = 2048;
byte data[] = new byte[BUFFER];
FileInputStream fi = new FileInputStream(tarFile);
try {
BufferedInputStream bis = new BufferedInputStream(fi, BUFFER);
boolean isWindowsPlatform = (System.getProperty("os.name").lastIndexOf("Windows") == -1);
try {
ArchiveInputStream tarInput = new ArchiveStreamFactory().createArchiveInputStream(bis);
try {
long fileLength = tarFile.length();
ArchiveEntry archiveEntry;
while ((archiveEntry = tarInput.getNextEntry()) != null) {
String entryName = archiveEntry.getName();
// dirty fix to be able to open windows cps files on linux/mac and the other way around
if (isWindowsPlatform) {
entryName = entryName.replaceAll("\\\\", "/");
} else {
entryName = entryName.replaceAll("/", "\\\\");
}
File entryFile = new File(entryName);
File entryFolder;
if (destinationFolder == null) {
entryFolder = entryFile.getParentFile();
} else {
entryFolder = (new File(destinationFolder, entryName)).getParentFile();
}
File destinationFile = new File(entryFolder, entryFile.getName());
if (archiveEntry.isDirectory()) {
destinationFile.mkdirs();
} else if (entryFolder.exists() || entryFolder.mkdirs()) {
FileOutputStream fos = new FileOutputStream(destinationFile);
try {
BufferedOutputStream bos = new BufferedOutputStream(fos);
try {
int count;
while ((count = tarInput.read(data, 0, BUFFER)) != -1) {
bos.write(data, 0, count);
if (waitingHandler != null && waitingHandler.isRunCanceled()) {
break;
}
}
} finally {
bos.close();
}
} finally {
fos.close();
}
if (waitingHandler != null) {
int progress = (int) (100 * tarInput.getBytesRead() / fileLength);
waitingHandler.setSecondaryProgressCounter(progress);
}
} else {
throw new IOException("Folder " + destinationFolder.getAbsolutePath()
+ " does not exist and could not be created. "
+ "Verify that you have the right to write in this directory.");
}
if (waitingHandler != null && waitingHandler.isRunCanceled()) {
break;
}
}
} finally {
tarInput.close();
}
} finally {
bis.close();
}
} finally {
fi.close();
}
}
}