I am using the below code to extract the files from zip archive.
public static List<String> unzipFiles(File zipFile, File targetDirectory) {
List<String> files = new ArrayList<String>();
BufferedOutputStream dest = null;
FileInputStream fileInputStream = null;
ZipInputStream zipInputStream = null;
try {
fileInputStream = new FileInputStream(zipFile);
zipInputStream = new ZipInputStream(new BufferedInputStream(
fileInputStream));
ZipEntry zipEntry;
int count = 0;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
log.debug("Extracting File Name :: " + zipEntry);
count++;
int length;
byte data[] = new byte[bufferGlb];
String fileName = zipEntry.getName();
File opFile = new File(targetDirectory, fileName);
FileOutputStream fileOutputStream = new FileOutputStream(opFile);
dest = new BufferedOutputStream(fileOutputStream, bufferGlb);
while ((length = zipInputStream.read(data, 0, bufferGlb)) != -1) {
dest.write(data, 0, length);
}
dest.flush();
files.add(fileName);
fileOutputStream.close();
}
log.debug("Total " + count + " Files Unziped Successfully ");
} catch (Exception e) {
log.error("Error occured in unzipping the file " + zipFile, e);
}
}
This code works fine with normal zip archives but not with zip64 archive. As far as I know that Java7/Java8 (ZipInputStream class) should support zip64 but am getting the below exception .
java.util.zip.ZipException: invalid entry size (expected 0 but got 21504 bytes)
at java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:384)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:196)
However am able to extract files from zip64 using the commons-compress ZipArchiveInputStream.
Any idea why the same can't be achieved using the Java API (ZipInputStream).
I want to extract two specific files from a .zip file. I tried the following library:
ZipFile zipFile = new ZipFile("myZip.zip");
Result:
Exception in thread "main" java.util.zip.ZipException: error in opening zip file
I also tried:
public void extract(String targetFileName) throws IOException
{
OutputStream outputStream = new FileOutputStream("targetFile.foo");
FileInputStream fileInputStream = new FileInputStream("myZip.zip");
ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(fileInputStream));
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null)
{
if (zipEntry.getName().equals("targetFile.foo"))
{
byte[] buffer = new byte[8192];
int length;
while ((length = zipInputStream.read(buffer)) != -1)
{
outputStream.write(buffer, 0, length);
}
outputStream.close();
break;
}
}
}
Result:
No exception, but an empty targetFile.foo file.
Note that the .zip file is of type SFX 7-zip and initially had the .exe extensions so that may be the reason for the failure.
As in Comments, Extracting SFX 7-Zip file is basically not supported with your library. But you can do with commons compress and xz Libary together with a quick "hack":
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
protected File un7zSFXFile(File file, String password)
{
SevenZFile sevenZFile = null;
File tempFile = new File("/tmp/" + file.getName() + ".temp");
try
{
FileInputStream in = new FileInputStream(file);
/**
* Yes this is Voodoo Code:
* first 205824 Bytes get skipped as these is are basically the 7z-sfx-runnable.dll
* common-compress does fail if this information is not cut away
* ATTENTION: the amount of bytes may vary depending of the 7z Version used!
*/
in.skip(205824);
// EndOfVoodoCode
tempFile.getParentFile().mkdirs();
tempFile.createNewFile();
FileOutputStream temp = new FileOutputStream(tempFile);
byte[] buffer = new byte[1024];
int length;
while((length = in.read(buffer)) > 0)
{
temp.write(buffer, 0, length);
}
temp.close();
in.close();
LOGGER.info("prepared exefile for un7zing");
if (password!=null) {
sevenZFile = new SevenZFile(tempFile, password.toCharArray());
} else {
sevenZFile = new SevenZFile(tempFile);
}
SevenZArchiveEntry entry;
boolean first = true;// accept only files with
while((entry = sevenZFile.getNextEntry()))
{
if(entry.isDirectory())
{
continue;
}
File curfile = new File(file.getParentFile(), entry.getName());
File parent = curfile.getParentFile();
if(!parent.exists())
{
parent.mkdirs();
}
FileOutputStream out = new FileOutputStream(curfile);
byte[] content = new byte[(int) entry.getSize()];
sevenZFile.read(content, 0, content.length);
out.write(content);
out.close();
}
}
catch(Exception e)
{
throw e;
}
finally
{
try
{
tempFile.delete();
sevenZFile.close();
}
catch(Exception e)
{
LOGGER.trace("error on cloasing Stream: " + sevenZFile.getDefaultName(), e);
}
}
}
Please acknowledge that this simple solution does only unpack in to the same directory as the as sfx-file is placed!
I have a zip file that contains a zip that includes folders to which I have to add some files. The structure is like
outerZip.zip
|folder
|innerZip.zip
|innerFolder
I need to add a few files to the inner folder.
I can return the innerZip ok, if I save it to file it shows the correct structure.
Now when I want to iterate through the ZipEntries of the innerZip for the first entry it shows to be /innerFolder, but when I want to add the entry content to the updated zip file it turns out that it contains data and throws the below error:
java.util.zip.ZipException: invalid entry CRC (expected 0x0 but got 0x46480bab)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:218)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at zip.builder.InnerBuilder.addFilesToInnerZip(InnerBuilder.java:179)
at zip.builder.InnerBuilder.addFilesToZip(InnerBuilder.java:117)
The code is here:
private byte[] addFilesToZip(byte[] outerZipBytes, Set<File> files) {
String zipPath = System.getProperty("catalina.home") + File.separator + "outerZipFile.zip";
File zipFile = new File(zipPath);
ZipFile outerZipFile = null;
try {
zipFile.createNewFile();
FileOutputStream fileout = new FileOutputStream(zipFile);
fileout.write(outerZipBytes);
fileout.close();
outerZipFile = new ZipFile(zipFile);
File innerZipFile = getInnerZipFile(outerZipFile);
addFilesToInnerZip(innerZipFile, files);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (outerZipFile != null)
outerZipFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// TODO convert updated outer zip file to byte array
return new byte[0];
}
private File getInnerZipFile(ZipFile outerZipFile) throws IOException {
String innerZipPath = System.getProperty("catalina.home") + File.separator + "innerZipFile.zip";
ZipEntry entry = outerZipFile.getEntry("folder/inner.zip");
InputStream innerZipInputStream = outerZipFile.getInputStream(entry);
FileOutputStream fout = new FileOutputStream(new File(innerZipPath));
byte[] buf = new byte[1024];
int data;
while ((data = innerZipInputStream.read(buf)) != -1) {
fout.write(buf, 0, data);
}
innerZipInputStream.close();
fout.close();
return new File(innerZipPath);
}
private void addFilesToInnerZip(File zipFile, Set<File> files) throws IOException {
File tempFile = File.createTempFile(zipFile.getName(), null);
tempFile.delete();
zipFile.renameTo(tempFile);
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(entry.getName()));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) { // line 179
out.write(buf, 0, len);
}
entry = zin.getNextEntry();
}
for (File file : files) {
InputStream in = new FileInputStream(file);
out.putNextEntry(new ZipEntry("innerFolder/"+ file.getName()));
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.closeEntry();
in.close();
}
zin.close();
out.close();
tempFile.delete();
}
Thanks for any help!
I have to unzip a zip data package which is addressed via an URL. (The URL and DataInputStream are correct!)
private void unZipIt(File baseDir, DataInputStream dis, PipedOutputStream pos) throws ZipException
{
byte[] buffer = new byte[1024];
String fileName = "";
File newFile;
FileOutputStream fos = null;
try
{
ZipInputStream zis = new ZipInputStream(dis);
ZipEntry ze = zis.getNextEntry();
if(ze==null)
{
System.out.println("first zip entry is null");
}
while (ze != null)
{
System.out.println("zip entry is not null");
fileName = ze.getName();
newFile = new File(baseDir + File.separator + fileName);
if (isSavFile(fileName))
{
System.out.println(fileName + "is savfile");
new File(newFile.getParent()).mkdirs();
fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0)
{
fos.write(buffer, 0, len);
}
// fos.close();
}
ze = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
// return true;
}
catch (IOException e)
{
// ex.printStackTrace();
log.error("unzipping '" + fileName + "'", e);
throw new ZipException(fileName, e);
// return false;
}
But it is not possible to get any of the zip entries. (first zip entry is null!)
With a FileOutputStream it worked perfectly. Because of the efficiency I am not allowed to store the file on the PC.
Anyone an idea?
Most likely the problem is with how you acquire the input stream you pass as dis to your unZipIt() method.
You should not receive a DataInputStream but rather a simple InputStream. ZipInputStream does not use nor expect input to be a DataInputStream.
Also when saving the content of an entry you should only read (and save) as many bytes as the length of the entry, not until there are more bytes.
I'm trying to extract .zip files and I'm using this code:
String zipFile = Path + FileName;
FileInputStream fin = new FileInputStream(zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
UnzipCounter++;
if (ze.isDirectory()) {
dirChecker(ze.getName());
} else {
FileOutputStream fout = new FileOutputStream(Path
+ ze.getName());
while ((Unziplength = zin.read(Unzipbuffer)) > 0) {
fout.write(Unzipbuffer, 0, Unziplength);
}
zin.closeEntry();
fout.close();
}
}
zin.close();
but the problem is that, while debugging, when the code reaches the while(!=null) part, the zin.getNextEntry() is always null so it doesnt extract anything..
The .zip file is 150kb.. How can I fix this?
The .zip exists
Code I use to dl the .zip:
URL=intent.getStringExtra("DownloadService_URL");
FileName=intent.getStringExtra("DownloadService_FILENAME");
Path=intent.getStringExtra("DownloadService_PATH");
File PathChecker = new File(Path);
try{
if(!PathChecker.isDirectory())
PathChecker.mkdirs();
URL url = new URL(URL);
URLConnection conexion = url.openConnection();
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
lenghtOfFile/=100;
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(Path+FileName);
byte data[] = new byte[1024];
long total = 0;
int count = 0;
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
total += count;
notification.setLatestEventInfo(context, contentTitle, "جاري تحميل ملف " + FileName + " " + (total/lenghtOfFile), contentIntent);
mNotificationManager.notify(1, notification);
}
output.flush();
output.close();
input.close();
You might have run into the following problem, which occurs, when reading zip files using a ZipInputStream: Zip files contain entries and additional structure information in a sequence. Furthermore, they contain a registry of all entries at the very end (!) of the file. Only this registry does provide full information about the correct zip file structure. Therefore, reading a zip file in a sequence, by using a stream, sometimes results in a "guess", which can fail. This is a common problem of all zip implementations, not only for java.util.zip. Better approach is to use ZipFile, which determines the structure from the registry at the end of the file. You might want to read http://commons.apache.org/compress/zip.html, which tells a little more details.
If the Zip is placed in the same directory as this exact source, named "91.zip", it works just fine.
import java.io.*;
import java.util.zip.*;
class Unzip {
public static void main(String[] args) throws Exception {
String Path = ".";
String FileName = "91.zip";
File zipFile = new File(Path, FileName);
FileInputStream fin = new FileInputStream(zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
int UnzipCounter = 0;
while ((ze = zin.getNextEntry()) != null) {
UnzipCounter++;
//if (ze.isDirectory()) {
// dirChecker(ze.getName());
//} else {
byte[] Unzipbuffer = new byte[(int) pow(2, 16)];
FileOutputStream fout = new FileOutputStream(
new File(Path, ze.getName()));
int Unziplength = 0;
while ((Unziplength = zin.read(Unzipbuffer)) > 0) {
fout.write(Unzipbuffer, 0, Unziplength);
}
zin.closeEntry();
fout.close();
//}
}
zin.close();
}
}
BTW
what is the language in that MP3, Arabic?
I had to alter the source to get it to compile.
I used the File constructor that takes two String arguments, to insert the correct separator automatically.
Try this code:-
private boolean extractZip(String pathOfZip,String pathToExtract)
{
int BUFFER_SIZE = 1024;
int size;
byte[] buffer = new byte[BUFFER_SIZE];
try {
File f = new File(pathToExtract);
if(!f.isDirectory()) {
f.mkdirs();
}
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(pathOfZip), BUFFER_SIZE));
try {
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
String path = pathToExtract +"/"+ ze.getName();
if (ze.isDirectory()) {
File unzipFile = new File(path);
if(!unzipFile.isDirectory()) {
unzipFile.mkdirs();
}
}
else {
FileOutputStream out = new FileOutputStream(path, false);
BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
try {
while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) {
fout.write(buffer, 0, size);
}
zin.closeEntry();
}catch (Exception e) {
Log.e("Exception", "Unzip exception 1:" + e.toString());
}
finally {
fout.flush();
fout.close();
}
}
}
}catch (Exception e) {
Log.e("Exception", "Unzip exception2 :" + e.toString());
}
finally {
zin.close();
}
return true;
}
catch (Exception e) {
Log.e("Exception", "Unzip exception :" + e.toString());
}
return false;
}
This code works fine for me. Perhaps you need to check that the zipFile String is valid?
String zipFile = "C:/my.zip";
FileInputStream fin = new FileInputStream(zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
System.out.println("got entry " + ze);
}
zin.close();
produced valid results on a 3.3Mb zip file.
This code seems to work correctly for me.
Are you sure that your zip file is a valid zip file? If the file does not exist or is not readable then you will get a FileNotFoundException, but if the file is empty or not a valid zip file, then you will get ze == null.
while ((ze = zin.getNextEntry()) != null) {
The zip that you specify isn't a valid zip file. The size of the entry is 4294967295
while ((ze = zin.getNextEntry()) != null) {
System.out.println("ze=" + ze.getName() + " " + ze.getSize());
UnzipCounter++;
This gives:
ze=595.mp3 4294967295
...
Exception in thread "main" java.util.zip.ZipException: invalid entry size (expected 4294967295 but got 341297 bytes)
at java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:386)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:156)
at java.io.FilterInputStream.read(FilterInputStream.java:90)
at uk.co.farwell.stackoverflow.ZipTest.main(ZipTest.java:29)
Try your code with a valid zip file.
I know it's late for answer but anyway ..
I think the problem is in
if(!PathChecker.isDirectory())
PathChecker.mkdirs();
it should be
if(!PathChecker.getParentFile().exists())
PathChecker.getParentFile().mkdirs();