package ef.impl.archive;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
/**
* User: sduchenko
* Date: 23.04.13
* Time: 18:45
*/
public class Archiver {
public static void createArchive(ArchiveType archiveType, Collection<File> files, File archiveFile) throws IOException {
ArchiveOutputStream aos;
switch (archiveType){
case TAR:
aos = new TarArchiveOutputStream(new FileOutputStream(archiveFile), "UTF-8");
((TarArchiveOutputStream)aos).setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
break;
case ZIP: aos = new ZipArchiveOutputStream(new FileOutputStream(archiveFile)); break;
default:
throw new IOException("archive type not supported");
}
Deque<Entry> stack = new LinkedList<Entry>();
putEntries(stack, null, files);
int entriesToClose = 0;
boolean wasError = false;
try {
while(!stack.isEmpty()){
Entry e = stack.pop();
ArchiveEntry entry = aos.createArchiveEntry(e.file, e.baseName);
aos.putArchiveEntry(entry);
entriesToClose++;
if(e.file.isDirectory()){
File[] list = e.file.listFiles();
if(list != null && list.length > 0){
putEntries(stack, e.baseName, list);
}
}else{
FileInputStream fis = new FileInputStream(e.file);
try {
IOUtils.copy(fis, aos);
} finally {
fis.close();
}
}
aos.closeArchiveEntry();
entriesToClose--;
}
} catch(Exception e){
wasError = true;
while(entriesToClose-- >0){
try {
aos.closeArchiveEntry();
} catch (IOException ignored) {}
}
if(e instanceof IOException){
throw (IOException) e;
}
throw new IOException(e);
} finally {
try {
aos.close();
} catch (IOException ignore) {}
if(wasError){
archiveFile.delete();
}
}
}
public static void extractArchive(ArchiveType archiveType, File srcFile, File dstDir) throws IOException {
ArchiveInputStream ais;
switch (archiveType){
case TAR:
ais = new TarArchiveInputStream(new FileInputStream(srcFile));
break;
case ZIP:
ais = new ZipArchiveInputStream(new FileInputStream(srcFile));
break;
default:
throw new IOException("archive type not supported");
}
ArchiveEntry entry;
try {
while((entry = ais.getNextEntry()) != null){
File file = new File(dstDir, entry.getName());
if(entry.isDirectory()){
if(!file.mkdirs()){
throw new IOException("unable to create directory tree: "+file.getPath());
}
continue;
}
FileOutputStream fos = new FileOutputStream(file);
try {
IOUtils.copy(ais, fos);
} finally {
try {
fos.close();
} catch (IOException ignored) {}
}
}
} finally {
try {
ais.close();
} catch (IOException ignored) {}
}
}
private static void putEntries(Deque<Entry> stack, String baseName, Collection<File> files){
baseName = baseName == null ? "" : baseName + "/";
for(File file: files){
stack.push(new Entry(baseName + file.getName(), file));
}
}
private static void putEntries(Deque<Entry> stack, String baseName, File[] files){
baseName = baseName == null ? "" : baseName + "/";
for(File file: files){
stack.push(new Entry(baseName + file.getName(), file));
}
}
private static class Entry {
String baseName;
File file;
Entry(String baseName, File file) {
this.baseName = baseName;
this.file = file;
}
}
}