How can i tar a directory and preserve the directory structure using the org.apache.commons.compress libraries?
With what i am doing below, i am just getting a package that has everything flattened.
Thanks!
Here is what i have been trying and it is not working.
public static void createTar(final String tarName, final List<File> pathEntries) throws IOException {
OutputStream tarOutput = new FileOutputStream(new File(tarName));
ArchiveOutputStream tarArchive = new TarArchiveOutputStream(tarOutput);
List<File> files = new ArrayList<File>();
for (File file : pathEntries) {
files.addAll(recurseDirectory(file));
}
for (File file : files) {
TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(file, file.getName());
tarArchiveEntry.setSize(file.length());
tarArchive.putArchiveEntry(tarArchiveEntry);
FileInputStream fileInputStream = new FileInputStream(file);
IOUtils.copy(fileInputStream, tarArchive);
fileInputStream.close();
tarArchive.closeArchiveEntry();
}
tarArchive.finish();
tarOutput.close();
}
public static List<File> recurseDirectory(final File directory) {
List<File> files = new ArrayList<File>();
if (directory != null && directory.isDirectory()) {
for (File file : directory.listFiles()) {
if (file.isDirectory()) {
files.addAll(recurseDirectory(file));
} else {
files.add(file);
}
}
}
return files;
}
Your problem is here:
TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(file, file.getName());
Because you put each file with only it's name, not his path, in the tar.
You need to pass the relative path from your path entries to this file instead of file.getName().
Related
Im looking to create a .tar.gz that contains sub directories that are .tar files.
I have two seperate things working right now, I am able to create a data.tar file with the needed information inside. I also have a .tar.gz working, but the subdirectories are not .tar files, for example:
data.tar (Working)
|-directory/
|--files
file.tar.gz (Working)
|-data/
|--directory/
|---files
Goal:
file.tar.gz (Not Working)
|-data.tar
|--directory/
|---files
To add a .tar to my .tar.gz i am doing the following creating a .tar file and then adding that .tar file to my .tar.gz
public class TarArchiveOutput extends Closeable {
public BufferedOutputStream bOut;
public GzipCompressorOutputStream gzOut;
public TarArchiveOutputStream tOut;
private boolean isZipped;
public TarArchiveOutput(OutputStream oStream, boolean zip) throws IOException {
bOut = null;
gzOut = null;
tOut = null;
isZipped = zip;
if(isZipped) {
bOut = new BufferedOutputStream(oStream, 1024 * 10240);
gzOut = new GzipCompressorOutputStream(bOut);
tOut = new TarArchiveOutputStream(gzOut);
tOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
} else {
bOut = new BufferedOutputStream(oStream, 1024 * 10240);
tOut = new TarArchiveOutputStream(bOut);
tOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
}
}
public void addFileToOutput(String path, String base) throws IOException {
File f = new File(path);
if(!base.endsWith("/"))
base = base+"/";
String entryName = base + f.getName();
TarArchiveEntry tarEntry = new TarArchiveEntry(f, entryName);
tOut.putArchiveEntry(tarEntry);
if (f.isFile()) {
IOUtils.copy(new FileInputStream(f), tOut);
tOut.closeArchiveEntry();
} else {
tOut.closeArchiveEntry();
File[] children = f.listFiles();
if (children != null) {
for (File child : children) {
addFileToOutput(child.getAbsolutePath(), entryName + "/");
}
}
}
}
#Override
public void close() {
if(isZipped) gzOut.close();
tOut.close();
bOut.close();
}
}
To create just a .tar file:
TarArchiveOutput dataTarOutput = new TarArchiveOutput(new FileOutputStream(new File("data.tar")), false);
//Add files
Creating .tar.gz
TarArchiveOutput tarGZOutput = new TarArchiveOutput(new FileOutputStream(new File("file.tar.gz")), true);
tarGZOutput.addFileToOutput("data.tar", "");
I expect the format to be as follows:
file.tar.gz
|-data.tar
|--directory/
|---files
The actual result is a .tar.gz that when uncompressed/untar it contains a data.tar file but when i try to untar that it turns into a data.tar.cpgz (infinite loop), can not uncompress. Thanks in advance any help would be great!
In order to GZip the TAR archive you need to do the following:
TarArchiveOutput dataTarGzOutput = new TarArchiveOutput(new GZIPOutputStream(new FileOutputStream(new File("data.tar.gz"))), false);
So i created a zip and created a new sub folder in the zip file by creating a zip entry that ends in "\". How would i write to the subfolder?
My problem is i have a putnextEntry call on my ZipOutputStream in a for loop so after the folder gets created i then jump into a for loop where the different zip files are written. But they are written at the same level as the subdir within the zip.
What i think is happening is because i use putNextEntry with the first actual zip(not dir) entry it is closing the subfolder and writing to the root of the zip. Any ideas?
Code below
private int endprocess() {
try {
zipFolder(ripPath, zipOutputPath, "rips");
//zipFolder(destPDFfiles, zipOutputPath, "pdfs");
this.returnCode = 0;
//log.debug ( "Accumulator count: " + acount);
log.debug("Equivest count: " + ecount);
//log.debug ( "Assoc count: " + scount);
processEndOfEnvelope();
} catch (Exception reportException) {
log.logError("Caught exception in creating.");
reportException.printStackTrace();
this.returnCode = 15;
}
return (this.returnCode);
}
public static void zipFolder(String srcFolder, String dest, String outputFolder){
try{
ZipOutputStream zos = null;
FileOutputStream fos = null;
fos = new FileOutputStream(dest + "\\newzip.zip");
zos = new ZipOutputStream(fos);
addFolderToZip(srcFolder, zos, outputFolder);
zos.flush();
zos.close();
}catch(IOException e){
log.logError("**********************");
log.logError("IO Exception occurred");
log.logError(e.getMessage());
e.printStackTrace();
}
}
private static void addFileToZip(String srcFile, ZipOutputStream zos, String outputFolder){
try {
File folder = new File(srcFile);
if (folder.isDirectory()) {
addFolderToZip(srcFile, zos, outputFolder);
} else {
byte[] buffer = new byte[1024];
int length;
FileInputStream fis = new FileInputStream(srcFile);
ZipEntry ze = new ZipEntry("C:\\AWDAAV\\zip\\newzip.zip\\" + outputFolder + "\\" + folder.getName());
zos.putNextEntry(ze);
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
}
}catch(Exception e){
log.logError("**********************");
log.logError("Exception occurred");
log.logError(e.getMessage());
e.printStackTrace();
}
}
private static void addFolderToZip(String srcFolder, ZipOutputStream zos, String outputFolder){
try{
File folder = new File(srcFolder);
zos.putNextEntry(new ZipEntry(outputFolder + "\\"));
for(String fileName : folder.list()){
addFileToZip(srcFolder + "\\" + fileName, zos, outputFolder);
}
}catch(Exception e){
log.logError("**********************");
log.logError("Exception occurred");
log.logError(e.getMessage());
e.printStackTrace();
}
}
I had a look at your code and i think the ZIP API works just as you think.
Only you had some logic errors with the path names.
You need to convert the path names from the local names to the relative locations in the zip file.
Maybe you got confused somewhere in that area.
Here is my suggestion:
File: org/example/Main.java
package org.example;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws IOException {
MyZip myZip = new MyZip();
Path sourcePath = Paths.get("C:/Users/David/Desktop/a");
Path targetPath = Paths.get("C:/Users/David/Desktop/zip/out.zip");
Path zipPath = Paths.get("tadaa");
myZip.zipFolder(sourcePath, targetPath.toFile(), zipPath);
}
}
Update: Explanation of variables in main method
The sourcePath is a directory which content you want to include in the zip archive.
The targetPath is the output path of the zip file. For example the new zip file will be created at exactly that location.
The zipPath is the subdirectory within the zip directory where your content from sourcePath will be placed. This variable may also be set to null. If it is null the sourcePath will be put in the root of the new zip archive.
File: org/example/MyZip.java
package org.example;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class MyZip {
public void zipFolder(Path base, File dest, Path zipFolder) throws IOException {
try (FileOutputStream fos = new FileOutputStream(dest);
ZipOutputStream zos = new ZipOutputStream(fos)) {
addFolderToZip(base.getParent(), base, zos, zipFolder);
}
}
private void addFolderToZip(Path base, Path currentFolder, ZipOutputStream zos, Path zipFolder) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(currentFolder)) {
for(Path path : stream) {
Path relativePath = base != null ? base.relativize(path) : path;
Path pathInZip = zipFolder != null ? zipFolder.resolve(relativePath) : relativePath;
if(path.toFile().isDirectory()) {
zos.putNextEntry(new ZipEntry(pathInZip.toString() + "/"));
// recurse to sub directories
addFolderToZip(base, path, zos, zipFolder);
} else {
addFileToZip(path, pathInZip, zos);
}
}
}
}
private void addFileToZip(Path sourcePath, Path pathInZip, ZipOutputStream zos) throws IOException {
byte[] buffer = new byte[1024];
int length;
try (FileInputStream fis = new FileInputStream(sourcePath.toFile())) {
ZipEntry ze = new ZipEntry(pathInZip.toString());
zos.putNextEntry(ze);
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
}
}
}
ZipEntry.setLevel(filepath[in your case, \folder]);
I'm writing a java program that will extract zip file and rename the file inside it to the zip file name. For example: the zip file name is zip.zip and the file inside it is content.txt. Here i want to extract the zip file and the content.txt has to be renamed to zip.txt. I'm trying the below program.
And here there would be only one file in the zip file
Zip.Java
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class zip {
private static final int BUFFER_SIZE = 4096;
public void unzip(String zipFilePath, String destDirectory) throws IOException {
File destDir = new File(destDirectory);
if (!destDir.exists()) {
destDir.mkdir();
}
ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry entry = zipIn.getNextEntry();
while (entry != null) {
String filePath = destDirectory + File.separator + entry.getName();
if (!entry.isDirectory()) {
// if the entry is a file, extracts it
extractFile(zipIn, filePath, zipFilePath);
} else {
// if the entry is a directory, make the directory
File dir = new File(filePath);
dir.mkdir();
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
zipIn.close();
}
private void extractFile(ZipInputStream zipIn, String filePath, String zipFilePath) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
byte[] bytesIn = new byte[BUFFER_SIZE];
int read = 0;
while ((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
File oldName = new File(filePath);
System.out.println(oldName);
String str = zipFilePath.substring(zipFilePath.lastIndexOf("\\") + 1, zipFilePath.lastIndexOf("."));
System.out.println(str);
File zipPath = new File(zipFilePath);
System.out.println(zipPath.getParent());
File newName = new File(zipPath.getParent() + "\\" + str);
System.out.println(newName);
if (oldName.renameTo(newName)) {
System.out.println("Renamed");
} else {
System.out.println("Not Renamed");
}
bos.close();
}
}
UnZip.Java
public class UnZip {
public static void main(String[] args) {
String zipFilePath = "C:\\Users\\u0138039\\Desktop\\Proview\\Zip\\New Companies Ordinance (Vol Two)_xml.zip";
String destDirectory = "C:\\Users\\u0138039\\Desktop\\Proview\\Zip";
zip unzipper = new zip();
try {
unzipper.unzip(zipFilePath, destDirectory);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Here i was able to extract the file but unable to rename it. please let me knw where am i going wrong and how to fix it.
Thanks
Close your BufferedOutputStream directly after the last write instruction (after the while loop). Only then will it release its lock on the file and will you be able to rename the file.
See: http://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html#close()
Is there any java code which extracts 'tgz' file.
I searched a lot but didn't get any. So i first converted it into tar file and then i used code to extract tar file.
But my tar file contains xml, sh and tgz files so it is getting stucked.
code is:
public class test1 {
public static void main(String[] args) throws Exception{
File file = new File("D:\\Delta\\Interactive\\qml_windows\\development\\onemedia\\");
final List<File> untaredFiles = new LinkedList<File>();
final InputStream is = new FileInputStream("D:\\onemedia\\onemedia-dal-504-v4.tar");
final TarArchiveInputStream debInputStream = (TarArchiveInputStream) new ArchiveStreamFactory().createArchiveInputStream("tar", is);
TarArchiveEntry entry = null;
while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null) {
final File outputFile = new File(file, entry.getName());
if (entry.isDirectory()) {
if (!outputFile.exists()) {
if (!outputFile.mkdirs()) {
throw new IllegalStateException(String.format("Couldn't create directory %s.", outputFile.getAbsolutePath()));
}
}
} else {
final OutputStream outputFileStream = new FileOutputStream(outputFile);
IOUtils.copy(debInputStream, outputFileStream);
outputFileStream.close();
}
untaredFiles.add(outputFile);
}
debInputStream.close();
}
}
This code extracts tar file.
Still i am getting error as:
Exception in thread "main" java.io.FileNotFoundException: D:\onemedia\onemedia_4\adload.tgz (The system cannot find the path specified)
For some reason I am getting an error saying that it can not find or load my main class, can anyone give me a reason for this?
package FindFile;
import java.io.File;
/**
*
* #author Kevin
*/
public class FindFile
{
public void listFilesAndFolders(String directoryName)
{
File directory = new File(directoryName);
File[] fList = directory.listFiles();
for (File file : fList)
{
System.out.println(file.getName());
}
}
public void listFiles(String directoryName)
{
File directory = new File(directoryName);
File[] fList = directory.listFiles();
for (File file : fList)
{
if (file.isFile())
{
System.out.println(file.getName());
}
}
}
public void listFolders(String directoryName)
{
File directory = new File(directoryName);
File[] fList = directory.listFiles();
for(File file : fList)
{
if (file.isDirectory())
{
System.out.println(file.getName());
}
}
}
public void listFilesAndFilesSubDirectories(String directoryName)
{
File directory = new File(directoryName);
File[] fList = directory.listFiles();
for (File file : fList)
{
if (file.isFile())
{
System.out.println(file.getAbsolutePath());
} else if (file.isDirectory())
{
listFilesAndFilesSubDirectories(file.getAbsolutePath());
}
}
}
public static void main(String[] args)
{
FindFile findFile = new FindFile();
final String directoryWindows = "C:\\test";
findFile.listFiles(directoryWindows);
}
}
Your class is fine, I think your "IDE" (Textpad ?) does not seem to manage compilation and running of java programs.
just look at the location where the compiler writes the class file, this should be something like:
FindFile/FindFile.class
Just go to the directory where the directory FindFile is, open a command line window and run your class like this:
java FindFile.FindFile
I suggest you to use a real IDE, eclipse for instance is a good one for java developing.
The problem could be your project set-up. If you are using an IDE like NetBeans or Eclipse you can define what .java file holds the main function for execution. If that is not set-up it will tell you there is no main function. What Nilesh Tailor tells you might as well be the problem, I haven't worked with Java for some time and I can't fully remember the function constraints regarding class definitions.