ZipInputStream check whether zip file valid before going to extract it - java

How we check whether zip file corrupted or valid Zip file before going to extract it
my code`
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public void unzip() {
FileInputStream fin = null;
ZipInputStream zin = null;
OutputStream fout = null;
File outputDir = new File(_location);
File tmp = null;
try {
fin = new FileInputStream(_zipFile);
zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
Log.d("Decompress", "Unzipping " + ze.getName());
if (ze.isDirectory()) {
dirChecker(ze.getName());
} else {
tmp = File.createTempFile( "decomp", ".tmp", outputDir );
fout = new BufferedOutputStream(new FileOutputStream(tmp));
DownloadFile.copyStream( zin, fout, _buffer, BUFFER_SIZE );
zin.closeEntry();
fout.close();
fout = null;
tmp.renameTo( new File(_location + ze.getName()) );
tmp = null;
}
}
zin.close();
zin = null;
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( tmp != null ) { try { tmp.delete(); } catch (Exception ignore) {;} }
if ( fout != null ) { try { fout.close(); } catch (Exception ignore) {;} }
if ( zin != null ) { try { zin.closeEntry(); } catch (Exception ignore) {;} }
if ( fin != null ) { try { fin.close(); } catch (Exception ignore) {;} }
}
}
`
this work fine with valid zipfile, but invalid zipfile it doesen't throw any exception not produce anything, but i need to confirm the validity of zip file before going to unzip it

I think it's pretty much useless for checking if the zip file is corrupted for two reasons:
Some zip files contain more bytes than just the zip part. For example, self-extracting archives have an executable part yet they're still valid zip.
The file can be corrupted without changing its size.
So, I suggest calculating the CRC for a guaranteed method of checking for corruption.

A Zip file will be valid as long as it has its zip entry catalog present. If you take the zip command, it will allow you to browse so long as the catalog is present. A parameter used for testing actually performs an extraction and CRC check.
What you can do is extract and do a CRC check on a temporary folder using the temp dir creation facility of Java. Then if it is all successful, commit the extract by copying the files from the temp dir to the final destination.

Related

Renaming .jar file prevents program from extracting files

I am attempting to store some resources for my program within the runnable jar created through Intellij and then extract those files at runtime after receiving some user input. The folders are located on the root of the jar. I have got it to successfully extract the files as intended but the problems begin when the jar is renamed. As in applic1.jar to applic2.jar. Does anyone know why it is behaving in this manner?
This is the method that performs the extractions. Modified version of: How can I get a resource "Folder" from inside my jar File?
File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
boolean inDirectory = false;
if (jarFile.isFile()) { //run in JAR
try {
JarFile jar = new JarFile(jarFile);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry currentJar = entries.nextElement();
String name = currentJar.getName();
Path currentFile = Paths.get(name).getFileName();
if (name.startsWith(oldPath.replaceAll(Pattern.quote("\\"), "/"))) {
if (currentJar.isDirectory()) {
Files.createDirectories(Paths.get(newPath));
inDirectory = true;
} else {
if (Files.notExists(Paths.get(newPath), LinkOption.NOFOLLOW_LINKS)) {
Files.createDirectories(Paths.get(newPath).getParent());
}
BufferedInputStream source = new BufferedInputStream(jar.getInputStream(currentJar));
File dest = new File(newPath + (inDirectory ? "\\" + currentFile : ""));
FileOutputStream fos = new FileOutputStream(dest);
int read;
while ((read = source.read()) != -1) {
fos.write(read);
fos.flush();
}
fos.close();
source.close();
}
}
}
jar.close();
} catch (IOException e) {
e.printStackTrace();
}
} else { //run in IDE
copyAndRename(oldPath, newPath);
}

java : corrupted zip file created when copy using nio

I have implement following code to copy file(binary file)
code
private void copyFileWithChannels(File aSourceFile, File aTargetFile) {
log("Copying files with channels.");
FileChannel inChannel = null;
FileChannel outChannel = null;
FileInputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = new FileInputStream(aSourceFile);
inChannel = inStream.getChannel();
outStream = new FileOutputStream(aTargetFile);
outChannel = outStream.getChannel();
long bytesTransferred = 0;
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(0, inChannel.size(), outChannel);
}
}
catch(FileNotFoundException e){
log.error("FileNotFoundException in copyFileWithChannels()",e);
}
catch (IOException e) {
log.error("IOException in copyFileWithChannels()",e);
}
catch (Exception e) {
log.error("Exception in copyFileWithChannels()",e);
}
finally {
try{
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
if (inStream != null) inStream.close();
if (outStream != null) outStream.close();
}catch(Exception e){
log.error("Exception in copyFileWithChannels() while closing the stream",e);
}
}
}
I have test code with one zip file. when i verify file I found that file which generated is corrupt(size was increased).
Source zip file is about 9GB.
Try this:
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(bytesTransferred, inChannel.size() - bytesTransferred, outChannel);
}
Also, I would refer to IOUtils implementation, as a reference
https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/FileUtils.java
specifically
private static void doCopyFile(final File srcFile, final File destFile, final boolean preserveFileDate)
The transferTo method's first argument gives the position from which to transfer, not relative to where the stream left off, but relative to the start of the file. Since you put 0 there it will always transfer from the start of the file. So that line needs to be
bytesTransferred += inChannel.transferTo(bytesTransferred , inChannel.size(), outChannel);
mavarazy mentioned in his answer he's not sure if you need a loop when using inChannel.size(), since the expectation is that if you supply the whole size it will copy the entire file. However, the actual transfer might be less than the requested number of bytes if the output channel's buffer has less room available. So you do need the loop as in his second code snippet.
Unless you have a good reason best to use Files.copy(Path, Path, CopyOption...).

zip file is being create but without any files in it

i copied this code directly from oracle website. i have two .png file inside d:\barcode. while i run this code myfigs.zip is created in d: drive but it is corruped and 0kb size.
code:-
public class Zip {
static final int BUFFER = 2048;
public static void main (String argv[]) {
try {
BufferedInputStream origin = null;
FileOutputStream dest = new
FileOutputStream("D:\\myfigs.zip");
CheckedOutputStream checksum = new
CheckedOutputStream(dest, new Adler32());
ZipOutputStream out = new
ZipOutputStream(new
BufferedOutputStream(checksum));
//out.setMethod(ZipOutputStream.DEFLATED);
byte data[] = new byte[BUFFER];
// get a list of files from current directory
File f = new File("D:\\barcode");
String files[] = f.list();
for (int i=0; i<files.length; i++) {
System.out.println("Adding: "+files[i]);
FileInputStream fi = new FileInputStream(files[i]);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(files[i]);
out.putNextEntry(entry);
int count;
while((count = origin.read(data, 0,
BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
}
out.close();
System.out.println("checksum: "+checksum.getChecksum().getValue());
} catch(Exception e) {
e.printStackTrace();
}
}
}
to add more information whenever i run the code in debug mode code is successfully compiled to FileInputStream fi line then it is stopped there. the error thrown is
java.io.FileNotFoundException: barcode.png (The system cannot find the file specified)
Adding: barcode.png
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
The exception says "file not found". Your "adding" print statement gives you the answer:
Adding: barcode.png
The file "barcode.png" is not the same as the file "D:\barcode\barcode.png". You're just looking for a file named "barcode.png" in whatever your current working directory is set to, and it isn't there.
As per the docs for list() and the conclusion you should have made from your observations of your printed output and exception:
Names denoting the directory itself and the directory's parent directory are not included in the result. Each string is a file name rather than a complete path.
So you need to either:
Change your working directory to "D:\barcode" first, or
Add the parent directory name ("D:\barcode") back to the beginning of your filename ("barcode.png") before opening it, or
Look at some of the other functions File has to offer and see if there's one that helps you avoid this problem entirely.
Couple other minor notes:
It should be no surprise that the zip file was empty, given that your code threw an exception before you wrote anything to it.
"whenever i run the code in debug mode code is successfully compiled to FileInputStream fi line then it is stopped there" - This terminology is not correct. Your error was not a compiler error, it was a runtime error. The code compiled just fine.
The root cause of your problem was blind modification of the code copied from the Oracle site. Note the original comment, "get a list of files from current directory" -- This code assumed the files came from the current working directory. When you added your own directory in, that was no longer the case, and the program broke.
You can use as below code for zip one file:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Create by Cuder
*
*/
public class SampleZipFile {
/**
* Create by Cuder
*/
public static void main(String[] args) {
ZipOutputStream zipOutputStream = null;
FileInputStream fileInputStream = null;
try {
File fileInput = new File(
"D:\\eclipse4.4\\workspace\\SampleJava\\resource\\sampleZipFile.txt");
File fileOutput = new File(
"D:\\eclipse4.4\\workspace\\SampleJava\\resource\\sampleZipFile.zip");
FileOutputStream fileOutputStream = new FileOutputStream(fileOutput);
zipOutputStream = new ZipOutputStream(fileOutputStream);
fileInputStream = new FileInputStream(fileInput);
ZipEntry entry = new ZipEntry(fileInput.getName());
zipOutputStream.putNextEntry(entry);
byte[] buf = new byte[1024];
int byteRead = 0;
while ((byteRead = fileInputStream.read(buf)) > 0) {
zipOutputStream.write(buf, 0, byteRead);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != fileInputStream) {
fileInputStream.close();
}
if (null != zipOutputStream) {
zipOutputStream.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

How to Read PNG from a jar packaged in a war

I am trying to write some code that allows me to access a file (specifically EMailBanner.png) that is wrapped as a jar and then included in a war.
The code I have cobbled together is as follows;
public static File getFile(String imagePath){
if(StringUtilities.stringEmptyOrNull(imagePath)){
throw new IllegalArgumentException("Invalid image path");
}
File tempFile = null;
InputStream is = null;
FileOutputStream fos = null;
try{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
is = classLoader.getResourceAsStream(imagePath);
tempFile = File.createTempFile("EMailBanner", ".png");
tempFile.deleteOnExit();
fos = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
}catch(IOException e ){
LOGGER.error("Unable to load image", e);
}catch(Exception e){
LOGGER.error("Unable to load image", e);
}finally{
try {
fos.close();
is.close();
} catch (IOException e) {
LOGGER.warn("Unable to close the file input / file output streams", e);
}
}
return tempFile;
}
The issue I am facing is that when deployed on to the development box as a war file - the application cannot find the png file. If I run locally in eclipse it isn't a problem.
Whats strange is I have a number of properties files in the resources folder as you can see from the image below;
I have no problems loading those from within the jar file - loaded like this;
public static Properties getDatabaseConnectionProps(ApplicationName appName) throws IOException{
if(appName == null){
throw new IllegalArgumentException("Path to proeprties file was null or empty");
}
Properties props = null;
try(InputStream resourceStream = DatabaseUtilities.class.getResourceAsStream("/vimba.properties")) {
if(resourceStream != null){
props = new Properties();
props.load(resourceStream);
return props;
}else{
throw new IllegalArgumentException("In invalid properties file path was provided");
}
} catch (IOException e) {
throw e;
}
}
So why would one approach work and potentially not the other? I am completely out of alternative options so really hope someone can save the day
Thanks
I have just tested something similar on my local machine using your code. It seems to work fine from what I can see.
The only other issue I can see is - if you check the JAR (you can de-compile it), make sure the image you are trying to retrieve is in there and that the filename matches.

ZipException: error in opening zip file

I'm working on a method which will take a zipped file, unzip it, and return a new file/directory containing all the unzipped files. The goal is to then take that directory and extract an excel document from it and then convert it into a Workbook class I built (which is fully unit tested and works fine). The problem is that I'm getting the following exception:
java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:215)
at java.util.zip.ZipFile.<init>(ZipFile.java:145)
at java.util.zip.ZipFile.<init>(ZipFile.java:159)
at com.atd.core.datamigrator.BulkImageUpload.createWorkbook(BulkImageUpload.java:54)
at com.atd.core.datamigrator.BulkImageUpload.importImages(BulkImageUpload.java:38)
at com.atd.core.datamigrator.BulkImageUpload.main(BulkImageUpload.java:236)
Here is my code
private Workbook createWorkbook(File file) {
File unZipedFile = unZip(file);
File[] files = unZipedFile.listFiles();
Workbook wBook = null;
for (int i = 0; i < files.length; i++) {
if (files[i].getName().contains(".xls")) {
try {
File f = files[i];
ZipFile zip = new ZipFile(f);
wBook = new Workbook(zip);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
return wBook;
}
private File unZip(File input) {
File output = new File("unzippedFile");
OutputStream out = null;
try {
ZipFile zipFile = new ZipFile(input);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File entryDestination = new File(output, entry.getName());
entryDestination.getParentFile().mkdirs();
InputStream in = zipFile.getInputStream(entry);
ZipInputStream zis = new ZipInputStream(in);
out = new FileOutputStream(entryDestination);
out.write(zis.read());
out.flush();
out.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return output;
}
I know this is a problem with the unzip method because when I use File f = new File("some path") instead of using the unzipped file, it works fine.
Also, File I/O was never my strong point, so be nice :)
Okay, I now believe that this is the problem:
ZipInputStream zis = new ZipInputStream(in);
out = new FileOutputStream(entryDestination);
out.write(zis.read());
out.flush();
out.close();
You're creating a new file, and writing a single byte to it. That's not going to be a valid Excel file of any description. You're also failing to close streams using finally blocks, but that's a different matter. To copy the contents of one stream to another, you want something like:
byte[] buffer = new byte[8192];
int bytes;
while ((bytes = input.read(buffer)) > 0) {
output.write(buffer, 0, bytes);
}
That said, you'd be better off using a 3rd party library to hide all of this detail - look at Guava and its ByteStreams and Files classes for example.
It's worth taking a step back and working out why you didn't spot this problem for yourself, by the way. For example, the first thing I'd have done would be to look at the directory where the files were unzipped, and try to open those files. Just seeing a bunch of 1-byte files would be a bit of a giveaway. When trying to diagnose an issue, it's vital that you can split a big problem into small ones, and work out which small one is at fault.

Categories

Resources