zip Files are not unzipping in the same folder? - java

Here i have folder(ZipFilesFolder) in that it consist of 10 zip files say one.zip,two.zip,three.zip..ten.zip,i'm passing file every time from this folder to zipFileToUnzip as zipFilename.I need the result in the same folder(ZipFilesFolder)i need to unzip those files and instead of one.zip,two.zip,..one,two,three folder has to visible.
public static void zipFileToUnzip(File zipFilename) throws IOException {
try {
//String destinationname = "D:\\XYZ";
byte[] buf = new byte[1024];
ZipInputStream zipinputstream = null;
ZipEntry zipentry;
zipinputstream = new ZipInputStream(new FileInputStream(zipFilename));
zipentry = zipinputstream.getNextEntry();
while (zipentry != null) {
//for each entry to be extracted
String entryName = zipentry.getName();
System.out.println("entryname " + entryName);
int n;
FileOutputStream fileoutputstream;
File newFile = new File(entryName);
String directory = newFile.getParent();
if (directory == null) {
if (newFile.isDirectory()) {
break;
}
}
fileoutputstream = new FileOutputStream(
destinationname + entryName);
while ((n = zipinputstream.read(buf, 0, 1024)) > -1) {
fileoutputstream.write(buf, 0, n);
}
fileoutputstream.close();
zipinputstream.closeEntry();
zipentry = zipinputstream.getNextEntry();
}//while
zipinputstream.close();
} catch (IOException e) {
}
}
This is my code ,but it is not working,could anybody help me,how to get desired output.

There are a couple of problems with your code:
it does not compile since destinationname is commented, but referenced when opening the FileOutputStream
IOExceptions are caught and ignored. If you throw them you would get error messages that could help you diagnose the problem
when opening the FileOutputStream, you just concatenate two strings without adding a path-separator in between.
if the file to be created is in a directory, the directory is not created and thus FileOutputStream cannot create the file.
streams are not closed when exceptions occur.
If you do not mind using guava, which simplifies life when it comes to copying streams to files, you could use this code instead:
public static void unzipFile(File zipFile) throws IOException {
File destDir = new File(zipFile.getParentFile(), Files.getNameWithoutExtension(zipFile.getName()));
try(ZipInputStream zipStream = new ZipInputStream(new FileInputStream(zipFile))) {
ZipEntry zipEntry = zipStream.getNextEntry();
if(zipEntry == null) throw new IOException("Empty or no zip-file");
while(zipEntry != null) {
File destination = new File(destDir, zipEntry.getName());
if(zipEntry.isDirectory()) {
destination.mkdirs();
} else {
destination.getParentFile().mkdirs();
Files.asByteSink(destination).writeFrom(zipStream);
}
zipEntry = zipStream.getNextEntry();
}
}
}
Alternatively you might also use zip4j, see also this question.

Related

Trouble with using ZipInputStream.getNextEntry() multiple times

I am trying to unzip specific files from a zip. I first get a ZipInputStream:
ZipInputStream zipIn = new ZipInputStream(new BufferedInputStream(new FileInputStream(filePath)));
Alright, this works! Now I want to extract two files, called F1 and F2, so I call
extractFileFromZip(zipIn, Path + "F1", "F1")
extractFileFromZip(zipIn, Path + "F2", "F2")
public static boolean extractFileFromZip(ZipInputStream inZip, String file, String name) throws Exception {
byte data[] = new byte[BUFFER_SIZE];
boolean found = false;
ZipEntry ze;
while((ze = inZip.getNextEntry()) != null) {
if(ze.getName().equals(name)) {
found = true;
// delete old file first
File oldFile = new File(file);
if(oldFile.exists()) {
if(!oldFile.delete()) {
throw new Exception("Could not delete " + file);
}
}
FileOutputStream outFile = new FileOutputStream(file);
int count = 0;
while((count = inZip.read(data)) != -1) {
outFile.write(data, 0, count);
}
outFile.close();
//inZip.closeEntry();
}
}
return true;
}
Now the problem is with inZip.getNextEntry(). For F1 it will cycle through all the files correctly and then give null. But for F2, it will just give null.
Why does this happen?
You're scanning the entire stream, consuming it. When you try to do it the second time, the stream is already at-end, so will do nothing.
Also, streaming all bytes in the zip file is slow, if you only want a small part of it.
Use a ZipFile instead, since it allows random access to the zip entries, so it is faster, and it allows reading the entries in random order.
Note: The code below has been changed to use Java 7+ features for better error handling, such as try-with-resources and NIO.2.
ZipFile zipFile = new ZipFile(filePath);
extractFileFromZip(zipFile, path + "F1", "F1");
extractFileFromZip(zipFile, path + "F2", "F2");
public static boolean extractFileFromZip(ZipFile zipFile, String file, String name) throws IOException {
ZipEntry ze = zipFile.getEntry(name);
if (ze == null)
return false;
Path path = Paths.get(file);
Files.deleteIfExists(path);
try (InputStream in = zipFile.getInputStream(ze)) {
Files.copy(in, path);
}
return true;
}
Alternatively, stream it only once, then check for both names in the while loop.
Map<String, String> nameMap = new HashMap<>();
nameMap.put("F1", path + "F1");
nameMap.put("F2", path + "F2");
extractFilesFromZip(filePath, nameMap);
public static void extractFilesFromZip(String filePath, Map<String, String> nameMap) throws IOException {
try (ZipInputStream zipIn = new ZipInputStream(new BufferedInputStream(new FileInputStream(filePath)))) {
for (ZipEntry ze; (ze = zipIn.getNextEntry()) != null; ) {
String file = nameMap.get(ze.getName());
if (file != null) {
Path path = Paths.get(file);
Files.deleteIfExists(path);
Files.copy(zipIn, path);
}
}
}
}
Because you read the entire stream to extract F1. So next time, for F2, getNextEntry() returned null. You need to either reopen the zip stream, or, better still, pass a list of files to unzip to your method.

How to unzip files stored in HDFS using Java, without first copying to the local file system?

We are storing zip files, containing XML files, in HDFS. We need to be able to programmatically unzip the file and stream out the contained XML files, using Java. FileSystem.open returns a FSDataInputStream but ZipFile constructors only take File or String as parameters. I really don't want to have to use FileSystem.copyToLocalFile.
Is it possible to stream the contents of a zip file stored in HDFS without first copying the zip file to the local file system? If so how?
Hi Please find the sample code,
public static Map<String, byte[]> loadZipFileData(String hdfsFilePath) {
try {
ZipInputStream zipInputStream = readZipFileFromHDFS(new Path(hdfsFilePath));
ZipEntry zipEntry = null;
byte[] buf = new byte[1024];
Map<String, byte[]> listOfFiles = new LinkedHashMap<>();
while ((zipEntry = zipInputStream.getNextEntry()) != null ) {
int bytesRead = 0;
String entryName = zipEntry.getName();
if (!zipEntry.isDirectory()) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while ((bytesRead = zipInputStream.read(buf, 0, 1024)) > -1) {
outputStream.write(buf, 0, bytesRead);
}
listOfFiles.put(entryName, outputStream.toByteArray());
outputStream.close();
}
zipInputStream.closeEntry();
}
zipInputStream.close();
return listOfFiles;
} catch (Exception e) {
e.printStackTrace();
}
}
protected ZipInputStream readZipFileFromHDFS(FileSystem fileSystem, Path path) throws Exception {
if (!fileSystem.exists(path)) {
throw new IllegalArgumentException(path.getName() + " does not exist");
}
FSDataInputStream fsInputStream = fileSystem.open(path);
ZipInputStream zipInputStream = new ZipInputStream(fsInputStream);
return zipInputStream;
}

Android unzip function not working

The following unzip finction doesn't work for all zip files.
My zip file pattern is as follows-
The Zip file contains one xml file and one folder(name- "images").
The name of the xml file is same as the zip file name.
The folder("images") may or may not contain any files.
I have validated the xml file before putting it into the zip file.
It throws exception at this line for some zip files-
FileOutputStream fout = new ileOutputStream(path.substring(0,path.length()-4)+"/"+filename);
The function is:
public boolean unZip(String path)
{
InputStream is;
ZipInputStream zis;
try
{
String filename;
is = new FileInputStream(path);
zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null)
{
filename = ze.getName();
if (ze.isDirectory()) {
File fmd = new File(path.substring(0,path.length()-4)+"/"+filename);
fmd.mkdirs();
continue;
}
FileOutputStream fout = new FileOutputStream(path.substring(0,path.length()-4)+"/"+filename);
while ((count = zis.read(buffer)) != -1)
{
fout.write(buffer, 0, count);
}
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
This method works fine. It was a permission issue while creating the zips in Linux platform. But function starts working properly when I changed the file permission.

Decompressing tar file with Apache Commons Compress

I'm using Apache Commons Compress to create tar archives and decompress them. My problems start with this method:
private void decompressFile(File file) throws IOException {
logger.info("Decompressing " + file.getName());
BufferedOutputStream outputStream = null;
TarArchiveInputStream tarInputStream = null;
try {
tarInputStream = new TarArchiveInputStream(
new FileInputStream(file));
TarArchiveEntry entry;
while ((entry = tarInputStream.getNextTarEntry()) != null) {
if (!entry.isDirectory()) {
File compressedFile = entry.getFile();
File tempFile = File.createTempFile(
compressedFile.getName(), "");
byte[] buffer = new byte[BUFFER_MAX_SIZE];
outputStream = new BufferedOutputStream(
new FileOutputStream(tempFile), BUFFER_MAX_SIZE);
int count = 0;
while ((count = tarInputStream.read(buffer, 0, BUFFER_MAX_SIZE)) != -1) {
outputStream.write(buffer, 0, count);
}
}
deleteFile(file);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
}
Every time I run the code, compressedFile variable is null, but the while loop is iterating over all entries in my test tar.
Could you help me to understand what I'm doing wrong?
From the official documentation
Reading entries from an tar archive:
TarArchiveEntry entry = tarInput.getNextTarEntry();
byte[] content = new byte[entry.getSize()];
LOOP UNTIL entry.getSize() HAS BEEN READ {
tarInput.read(content, offset, content.length - offset);
}
I have written an example starting from your implementation and testing with a very trivial .tar (just one entry of text).
Not knowing the exact requirement I just take care of solving the problem of reading the archive avoiding the nullpointer. Debugging, the entry is available as you also have found
private static void decompressFile(File file) throws IOException {
BufferedOutputStream outputStream = null;
TarArchiveInputStream tarInputStream = null;
try {
tarInputStream = new TarArchiveInputStream(
new FileInputStream(file));
TarArchiveEntry entry;
while ((entry = tarInputStream.getNextTarEntry()) != null) {
if (!entry.isDirectory()) {
File compressedFile = entry.getFile();
String name = entry.getName();
int size = 0;
int c;
while (size < entry.getSize()) {
c = tarInputStream.read();
System.out.print((char) c);
size++;
}
(.......)
AS I said: I tested with a tar including only an entry of text (you can also try this approach to verify the code) to be sure that the null is avoided.
You need to make all the needed adaptations for your real needs.
It is clear that you will have to handle streams as in the metacode I posted on top.
It shows how to deal with the single entries.
Try using getNextEntry() method instead of getNextTarEntry() method.
The second method returns a TarArchiveEntry. Probably this is not what you want!

Overwriting ZipEntrys

Simple question,
I'm writing a series of text files into a zip, just wrapping a fileoutputstream in a zipoutputstream and then in a printwriter.
public static int saveData(File outfile, DataStructure input) {
//variables
ArrayList<String> out = null;
FileOutputStream fileout = null;
ZipOutputStream zipout = null;
PrintWriter printer = null;
//parameter tests
try {
fileout = new FileOutputStream(outfile);
zipout = new ZipOutputStream(fileout);
printer = new PrintWriter(zipout);
} catch (Exception e) {
e.printStackTrace();
return util.FILE_INVALID;
}
for(DataItem data : input){
//process the data into a list of strings
try {
zipout.putNextEntry(new ZipEntry( dataFileName ));
for(String s : out) {
printer.println(s);
}
zipout.closeEntry();
} catch (Exception e) {
try {
fileout.close();
} catch (Exception x) {
x.printStackTrace();
return util.CRITICAL_ERROR;
}
e.printStackTrace();
return util.CRITICAL_ERROR;
}
}
try {
fileout.close();
} catch (Exception e) {
e.printStackTrace();
return util.CRITICAL_ERROR;
}
return util.SUCCESS;
}
Previously in the app i've been developing I've just been saving to the current directory for testing and I know in the case of a file already existing that the file will be overwritten (and have been exploiting this). What I dont know is the behaviour for zips. Will it overwrite entries of the same name? Or will it simply overwrite the whole zip file (which would be convenient for my purposes.
K.Barad
As Joel said, If you try to add a duplicate ZipEntry you will get an exception. If you want to replace the current entry you need to delete it and re-insert it.
You might want to do something like here below to achieve it:
private ZipFile addFileToExistingZip(File zipFile, File versionFile) throws IOException{
// get a temp file
File tempFile = File.createTempFile(zipFile.getName(), null);
// delete it, otherwise you cannot rename your existing zip to it.
tempFile.delete();
boolean renameOk=zipFile.renameTo(tempFile);
if (!renameOk)
{
throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
}
byte[] buf = new byte[4096 * 1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean toBeDeleted = false;
if (versionFile.getName().indexOf(name) != -1) {
toBeDeleted = true;
}
if(!toBeDeleted){
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
// Compress the files
InputStream in = new FileInputStream(versionFile);
String fName = versionFile.getName();
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(fName));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
// Complete the ZIP file
out.close();
tempFile.delete();
return new ZipFile(zipFile);
}
The above code worked for me where the need was to add a new zip entry to an existing zip file. If the entry is already present inside the zip, then overwrite it.
Comments/improvements in the code are welcome!
Thanks!
If you try to add a duplicate ZipEntry you will get an exception. If you want to replace the current entry you need to delete it and re-insert it. I suspect the exception you get is much the same as this one.

Categories