I have a simple code to extract zip files, it was working just fine as expected but during my test I tried my code with some zip files (fonts, icons and templates I downloaded from internet) just to make sure it should extract any zip files provided, but its not working with some zip files, here is the minimized code to regenerate this issue:
package com.test.mytest;
import java.io.FileInputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class ZipExtractTest {
public static final String ZIP_FILE = "/Users/XXXXX/Downloads/janne.zip";
public static void main(String[]args) {
unzipFile(ZIP_FILE);
unzipStream(ZIP_FILE);
}
public static void unzipFile(String zipName) {
try {
ZipFile zf = new ZipFile(zipName);
Enumeration ent = zf.entries();
while(ent.hasMoreElements()) {
System.out.println(ent.nextElement());
}
} catch(Exception e) {
System.out.println(e);
}
}
public static void unzipStream(String zipName) {
try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipName));
ZipEntry ze = zis.getNextEntry();
if(ze == null) {
System.out.println("unable to get first entry from zip file");
zis.close();
return;
}
while(ze != null) {
System.out.println("Entry Found: " + ze);
ze = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
} catch(Exception e) {
System.out.println(e);
}
}
}
actually In my real application i have to extract zip files through inputstreams. In the code above I am trying to extract "janne.zip" I downloaded this file from http://www.iconian.com/fonts/janne.zip I am able to extract it using any zip-tool and surprisingly through "unzipFile(String zipName)" method as well, but with unzipStream(String zipName) method
ZipEntry ze = zis.getNextEntry();
returns null
any help would be appreciated
Not an answer as to why this particular file doesn't work with java.util.zip
, but if you have the option to replace your use of java.util.zip.ZipInputStream
with the Apache commons-compress org.apache.commons.compress.archivers.zip.ZipArchiveInputStream
(which should be API-compatible) then I've just tested that on your example file and it seems to work successfully.
Generally I find commons-compress to be much more reliable than java.util.zip
at unpacking files created by tools other than the java.util.zip
classes themselves.
Edit: I've done a bit of debugging in Eclipse and it looks like this particular zip file has a single segment spanning marker of 0x30304b50
before the LOC signature (0x04034b50
) of the first entry's local header. This is something that commons-compress knows how to handle but java.util.zip
doesn't - if j.u.z.ZipInputStream
sees anything other than a LOC signature then getNextEntry()
will return null
.
Funny!
I debugged your code and got the same error. I found an header check in the ZipInputStream implementation, but not in the ZipFile implementation.
Dont ask me why, but the header in your zip file is not valid!
Your file is starting with: 50 4B 30 30 50 4B 03 04
A valid Zip File Header is: 50 4B 03 04
If you delete the first bytes (50 4B 30 30
) from your file you got a valid header an you can read you file!
I was having the same problem ! Lucky for me I was able to resolve it.
first i reset the blob data in the database then used java code to zip it using ZipInputStream. Although I am not sure, the null ZipEntry problem could be because of 2 things:
1. The blob data in the database is not stored correctly (or may be its already compressed, some databases compress blob data at the time of storage. you can google this too).
2. The input/output streams can also cause trouble, see this
Here is detailed description of what I did:
1. reset the blob field in database using EMPTY_BLOB and commit changes
2. used the below java program to update the blob field with a .xls file
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver ()); // register driver
Connection conn =
DriverManager.getConnection ("jdbc:oracle:thin:@my-local-database:1521:test", "test1", "test1");
// It's faster when auto commit is off:
conn.setAutoCommit (false);
try
{
PreparedStatement pstmt = conn.prepareStatement("update content set file_content = ? where CONTENT_ID=2006");
File blob = new File("C:/Users/ankur/Desktop/Book1.xls");
FileInputStream in = new FileInputStream(blob);
pstmt.setBinaryStream(1, in);
pstmt.executeUpdate();
conn.commit();
conn.close();
System.out.println("file updated");
}
catch (SQLException e)
{
e.printStackTrace();
}
Please note that the above code will work but it absolutely does not demonstrate coding standards and practices.
3. Used the below zip method to compress data
public byte[] zipByteArray(String primaryKey, byte[] input) throws IOException{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
ZipEntry entry = new ZipEntry(primaryKey);
entry.setSize(input.length);
zos.putNextEntry(entry);
zos.write(input);
zos.closeEntry();
zos.close();
return baos.toByteArray();
}
The above method takes a byte array, zips it, puts it into a ByteArrayOutputStream. You can choose to use the ByteArrayOutputStream itself, due to some requirements I am converting it to byte array.
4. I then insert the above byte array in blob field using prepared statement
5. If I use the unzip code given below, it works fine!
public byte[] unzipInputStream(InputStream is) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = null;
ZipInputStream zipIs = new ZipInputStream(new BufferedInputStream(is));
byteArrayOutputStream = new ByteArrayOutputStream();
ZipEntry entry = zipIs.getNextEntry();
while (entry != null) {
byte[] tmp = new byte[2048];
BufferedOutputStream bos = null;
bos = new BufferedOutputStream(byteArrayOutputStream);
int size = 0;
while ((size = zipIs.read(tmp)) != -1) {
bos.write(tmp, 0, size);
}
bos.flush();
bos.close();
entry = zipIs.getNextEntry();
}
zipIs.close();
return byteArrayOutputStream.toByteArray();
The output of the above method is the unzipped data.