I have the following code and it's OK when creating an encrypted zip file with the given file, however, I could not open the generated zip file with unzip command and it complains invalid zip.
"The Unarchiver" could not unzip as well.
public void encrypt(String desKey, String zipFileName, String fileName) {
InputStream inputStream = null;
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream(zipFileName);
SecretKey keySpec = new SecretKeySpec(desKey.getBytes(), "DESede");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
InputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher);
ZipInputStream zipInputStream = new ZipInputStream(cipherInputStream);
ZipEntry nextEntry = zipInputStream.getNextEntry();
inputStream = zipInputStream;
if (nextEntry == null) {
System.out.println("error");
inputStream = null;
}
fileOutputStream = new FileOutputStream(fileName);
IOUtils.copy(inputStream, fileOutputStream);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
} else if (fileInputStream != null) {
fileInputStream.close();
} else if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Zipping a stream does not means that you create a zip file... If you want to create a zip file with a crypted file in it, you should create ZipEntry, add it to the ZipOutputStream and then push your encrypted data. You can have a look at http://www.oracle.com/technetwork/articles/java/compress-1565076.html wich is a good starting point.
Related
we have a piece of code which generates a zip file on our system. Everything is ok, but sometimes this zip file while opened by FilZip or WinZip is considered to be corrupted.
So here is my question: how can we check programatically if a generated zip file is corrupted?
Here is the code we are using to generate our zip files:
try {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpFile));
byte[] buffer = new byte[16384];
int contador = -1;
for (DigitalFile digitalFile : document.getDigitalFiles().getContent()) {
ZipEntry entry = new ZipEntry(digitalFile.getName());
FileInputStream fis = new FileInputStream(digitalFile.getFile());
try {
zos.putNextEntry(entry);
while ((counter = fis.read(buffer)) != -1) {
zos.write(buffer, 0, counter);
}
fis.close();
zos.closeEntry();
} catch (IOException ex) {
throw new OurException("It was not possible to read this file " + arquivo.getId());
}
}
try {
zos.close();
} catch (IOException ex) {
throw new OurException("We couldn't close this stream", ex);
}
Is there anything we are doing wrong here?
EDIT:
Actually, the code above is absolutely ok. My problem was that I was redirecting the WRONG stream for my users. So, instead of opening a zip file they where opening something completely different. Mea culpa :(
BUT the main question remains: how programatically I can verify if a given zip file is not corrupted?
You can use the ZipFile class to check your file :
static boolean isValid(final File file) {
ZipFile zipfile = null;
try {
zipfile = new ZipFile(file);
return true;
} catch (IOException e) {
return false;
} finally {
try {
if (zipfile != null) {
zipfile.close();
zipfile = null;
}
} catch (IOException e) {
}
}
}
I know its been a while that this has been posted, I have used the code that all of you provided and came up with this. This is working great for the actual question. Checking if the zip file is corrupted or not
private boolean isValid(File file) {
ZipFile zipfile = null;
ZipInputStream zis = null;
try {
zipfile = new ZipFile(file);
zis = new ZipInputStream(new FileInputStream(file));
ZipEntry ze = zis.getNextEntry();
if(ze == null) {
return false;
}
while(ze != null) {
// if it throws an exception fetching any of the following then we know the file is corrupted.
zipfile.getInputStream(ze);
ze.getCrc();
ze.getCompressedSize();
ze.getName();
ze = zis.getNextEntry();
}
return true;
} catch (ZipException e) {
return false;
} catch (IOException e) {
return false;
} finally {
try {
if (zipfile != null) {
zipfile.close();
zipfile = null;
}
} catch (IOException e) {
return false;
} try {
if (zis != null) {
zis.close();
zis = null;
}
} catch (IOException e) {
return false;
}
}
}
I think you'll see correspondent exception stack trace during zip-file generation. So, you probably wan't to enhance your exception handling.
in my implementation it looks like that. maybe it helps you:
//[...]
try {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
zos.putNextEntry(new ZipEntry(file.getName()));
try {
final byte[] buf = new byte[BUFFER_SIZE];
while (true) {
final int len = bis.read(buf);
if (len == -1) {
break;
}
zos.write(buf, 0, len);
}
zos.flush();
zos.closeEntry();
} finally {
try {
bis.close();
} catch (IOException e) {
LOG.debug("Buffered Stream closing failed");
} finally {
fis.close();
}
}
} catch (IOException e) {
throw new Exception(e);
}
//[...]
zos.close
Perhaps swap the following two lines?;
fis.close();
zos.closeEntry();
I can imagine that the closeEntry() will still read some data from the stream.
Your code is basically OK, try to find out which file is responsible for the corrupted zip file. Check whether digitalFile.getFile() always returns a valid and accessible argument to FileInputStream. Just add a bit logging to your code and you will find out what's wrong.
new ZipFile(file)
compress again the file, so duplicate efforts and that is not what you are looking for. Despite of the fact that only check one file and the question compress n-files.
Take a look to this: http://www.kodejava.org/examples/336.html
Create a checksum for your zip:
CheckedOutputStream checksum = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum));
...
And when you finish the compression show it
System.out.println("Checksum : " + checksum.getChecksum().getValue());
You must do the same reading the zip with java or others tools checking if checksums match.
see https://stackoverflow.com/a/10689488/848072 for more information
ZipOutputStream does not close the underlying stream.
What you need to do is:
FileOutputStream fos = new FileOutputStream(...);
ZipOutputStream zos = new ZipOutputStream(fos);
Then in your closing block:
zos.close();
fos.flush(); // Can't remember whether this is necessary off the top of my head!
fos.close();
How can we store the KEY in a key file for AES encryption using java so that the key file can be used for decryption purpose.
private static void storeKey(SecretKey key){
byte[] keyb = key.getEncoded();
FileOutputStream keyfos;
try {
File file = new File(generateKeyFilesPath);
if (!file.exists()) {
file.createNewFile();
}
keyfos = new FileOutputStream(file);
keyfos.write(keyb);
keyfos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static SecretKeySpec getKey(String generateKeyFilesPath){
SecretKeySpec key = null;
try {
File keyFile = new File(path);
FileInputStream stream = new FileInputStream(keyFile);
byte[] bytesArray = new byte[(int) keyFile.length()];
stream.read(bytesArray);
stream.close();
key = new SecretKeySpec(bytesArray, "AES");
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
Unable to decrypt the cipher using the stored key(file),
Context
I am adapting parts of an existing project to a gae project. The original project uses FileInputStream and FileOutputStream but since gae doesn't accept FileOutputStream I am replacing them with ByteArrayInputStream and ByteArrayOutputStream. The original code loaded some local files and I replaced those with Datastore Entities that hold the content of those files in one of their properties.
Problem
It mostly seems to work but I get an ArrayIndexOutOfBoundsException in this piece of code:
private byte[] loadKey(Entity file) {
byte[] b64encodedKey = null;
ByteArrayInputStream fis = null;
try {
fis = fileToStreamAdapter.objectToInputStreamConverter(file);
b64encodedKey = new byte[(int) fis.available()];
fis.read(b64encodedKey);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return b64encodedKey;
}
fileToStreamAdapter.objectToInputStreamConverter(file) takes a Datastore Entity and turns the content of one of its properties into a ByteArrayInputStream.
The original code:
private byte[] loadKey(String path) {
byte[] b64encodedKey = null;
File fileKey = new File(path);
FileInputStream fis = null;
try {
fis = new FileInputStream(fileKey);
b64encodedKey = new byte[(int) fileKey.length()];
fis.read(b64encodedKey);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return b64encodedKey;
}
Is there something I'm missing in the differences between FileInputStream and ByteArrayInputStream that could cause this error?
It seems to me that if objectToInputStreamConverter created the ByteArrayInputStream using ByteArrayInputStream(byte[] buf) then it could just return the byte[] argument and save you from the need to read anything more, not to mention all that error handling.
fis.available() is not the size of the input stream, just how much data available in the buffer at this point.
If you need to return bytes from input stream you have to copy it by using something like this:
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int l;
byte[] data = new byte[16384];
while ((l = fis.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, l);
}
buffer.flush();
return buffer.toByteArray();
Or better us IOUtils from commons-io
I am using Hibernate. I have mapped my column nIcon VARBINARY(MAX) in my object as the following
#Column(columnDefinition="binary")
public byte[] getNicon() {
return this.nicon;
}
The method getByteArrayFromFile() is used to get the bytes from an image file, which I successfully write to the database.
public static byte[] getByteArrayFromFile(String absoluteFilePath) {
byte [] byteArray = null;
File file = new File(absoluteFilePath);
byteArray = new byte[(int) file.length()];
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
fileInputStream.read(byteArray);
} catch (FileNotFoundException e) {
logger.error(getStackTrace(e));
e.printStackTrace();
} catch (IOException e) {
logger.error(getStackTrace(e));
e.printStackTrace();
}finally {
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
logger.error(getStackTrace(e));
e.printStackTrace();
}
}
}
return byteArray;
}
The method getFileFromByteArray() is used to write the image file from the byte array that I retrieve from the database.
public static boolean getFileFromByteArray(String fileName, byte [] byteArray) {
boolean isSuccessful = false;
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(fileName);
fileOutputStream.write(byteArray);
isSuccessful = true;
} catch (FileNotFoundException e) {
logger.error(getStackTrace(e));
e.printStackTrace();
} catch (IOException e) {
logger.error(getStackTrace(e));
e.printStackTrace();
} finally {
if (fileOutputStream !=null) {
try {
fileOutputStream.close();
} catch (IOException e) {
logger.error(getStackTrace(e));
e.printStackTrace();
}
}
}
return isSuccessful;
}
My problem is that I am using binary to store the file. I would like to use the IMAGE type in MS SQL Server.
I know that the Hibernate mapping #LOB can be used to store the image as IMAGE type.
BUT I am having problems while writing the bytes back to file.
I am trying to write a class that can compress data. The below code fails (no exception is thrown, but the target .gz file is empty.)
Besides: I don't want to generate the .gz file directly like it is done in all examples. I only want to get the compressed
data, so that I can e.g. encrypt it before writting the data to a file.
If I write directly to a file everything works fine:
import java.io.*;
import java.util.zip.*;
import java.nio.charset.*;
public class Zipper
{
public static void main(String[] args)
{
byte[] dataToCompress = "This is the test data."
.getBytes(StandardCharsets.ISO_8859_1);
GZIPOutputStream zipStream = null;
FileOutputStream fileStream = null;
try
{
fileStream = new FileOutputStream("C:/Users/UserName/Desktop/zip_file.gz");
zipStream = new GZIPOutputStream(fileStream);
zipStream.write(dataToCompress);
fileStream.write(compressedData);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try{ zipStream.close(); }
catch(Exception e){ }
try{ fileStream.close(); }
catch(Exception e){ }
}
}
}
But, if I want to 'bypass' it to the byte array stream it does not produce a single byte - compressedData is always empty.
import java.io.*;
import java.util.zip.*;
import java.nio.charset.*;
public class Zipper
{
public static void main(String[] args)
{
byte[] dataToCompress = "This is the test data."
.getBytes(StandardCharsets.ISO_8859_1);
byte[] compressedData = null;
GZIPOutputStream zipStream = null;
ByteArrayOutputStream byteStream = null;
FileOutputStream fileStream = null;
try
{
byteStream = new ByteArrayOutputStream(dataToCompress.length);
zipStream = new GZIPOutputStream(byteStream);
zipStream.write(dataToCompress);
compressedData = byteStream.toByteArray();
fileStream = new FileOutputStream("C:/Users/UserName/Desktop/zip_file.gz");
fileStream.write(compressedData);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try{ zipStream.close(); }
catch(Exception e){ }
try{ byteStream.close(); }
catch(Exception e){ }
try{ fileStream.close(); }
catch(Exception e){ }
}
}
}
The problem is that you are not closing the GZIPOutputStream. Until you close it the output will be incomplete.
You just need to close it before reading the byte array. You need to reorder the finally blocks to achieve this.
import java.io.*;
import java.util.zip.*;
import java.nio.charset.*;
public class Zipper
{
public static void main(String[] args)
{
byte[] dataToCompress = "This is the test data."
.getBytes(StandardCharsets.ISO_8859_1);
try
{
ByteArrayOutputStream byteStream =
new ByteArrayOutputStream(dataToCompress.length);
try
{
GZIPOutputStream zipStream =
new GZIPOutputStream(byteStream);
try
{
zipStream.write(dataToCompress);
}
finally
{
zipStream.close();
}
}
finally
{
byteStream.close();
}
byte[] compressedData = byteStream.toByteArray();
FileOutputStream fileStream =
new FileOutputStream("C:/Users/UserName/Desktop/zip_file.gz");
try
{
fileStream.write(compressedData);
}
finally
{
try{ fileStream.close(); }
catch(Exception e){ /* We should probably delete the file now? */ }
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
I do not recommend inititalizing the stream variables to null, because it means your finally block can also throw a NullPointerException.
Also note that you can declare main to throw IOException (then you would not need the outermost try statement.)
There is little point in swallowing exceptions from zipStream.close();, because if it throws an exception you will not have a valid .gz file (so you should not proceed to write it.)
Also I would not swallow exceptions from byteStream.close(); but for a different reason - they should never be thrown (i.e. there is a bug in your JRE and you would want to know about that.)
I've improved JITHINRAJ's code - used try-with-resources:
private static byte[] gzipCompress(byte[] uncompressedData) {
byte[] result = new byte[]{};
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(uncompressedData.length);
GZIPOutputStream gzipOS = new GZIPOutputStream(bos)) {
gzipOS.write(uncompressedData);
// You need to close it before using bos
gzipOS.close();
result = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private static byte[] gzipUncompress(byte[] compressedData) {
byte[] result = new byte[]{};
try (ByteArrayInputStream bis = new ByteArrayInputStream(compressedData);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
GZIPInputStream gzipIS = new GZIPInputStream(bis)) {
byte[] buffer = new byte[1024];
int len;
while ((len = gzipIS.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
result = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
If you are still looking an answer you can use the below code to get the compressed byte[] using deflater and decompress it using inflater.
public static void main(String[] args) {
//Some string for testing
String sr = new String("fsdfesfsfdddddddsfdsfssdfdsfdsfdsfdsfdsdfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghghghghggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggfsdfesfsfdddddddsfdsfssdfdsfdsfdsfdsfdsdfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghghghghggggggggggggggggggggggggggggggggggggggggg");
byte[] data = sr.getBytes();
System.out.println("src size "+data.length);
try {
compress(data);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] compress(byte[] data) throws IOException {
Deflater deflater = new Deflater();
deflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
byte[] output = outputStream.toByteArray();
System.out.println("Original: " + data.length );
System.out.println("Compressed: " + output.length );
return output;
}
To compress
private static byte[] compress(byte[] uncompressedData) {
ByteArrayOutputStream bos = null;
GZIPOutputStream gzipOS = null;
try {
bos = new ByteArrayOutputStream(uncompressedData.length);
gzipOS = new GZIPOutputStream(bos);
gzipOS.write(uncompressedData);
gzipOS.close();
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
assert gzipOS != null;
gzipOS.close();
bos.close();
}
catch (Exception ignored) {
}
}
return new byte[]{};
}
To uncompress
private byte[] uncompress(byte[] compressedData) {
ByteArrayInputStream bis = null;
ByteArrayOutputStream bos = null;
GZIPInputStream gzipIS = null;
try {
bis = new ByteArrayInputStream(compressedData);
bos = new ByteArrayOutputStream();
gzipIS = new GZIPInputStream(bis);
byte[] buffer = new byte[1024];
int len;
while((len = gzipIS.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
assert gzipIS != null;
gzipIS.close();
bos.close();
bis.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
return new byte[]{};
}
You can use the below function, it is tested and working fine.
In general, your code has serious problem of ignoring the exceptions! returning null or simply not printing anything in the catch block will make it very difficult to debug
You do not have to write the zip output to a file if you want to process it further (e.g. encrypt it), you can easily modify the code to write the output to in-memory stream
public static String zip(File inFile, File zipFile) throws IOException {
FileInputStream fis = new FileInputStream(inFile);
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zout = new ZipOutputStream(fos);
try {
zout.putNextEntry(new ZipEntry(inFile.getName()));
byte[] buffer = new byte[BUFFER_SIZE];
int len;
while ((len = fis.read(buffer)) > 0) {
zout.write(buffer, 0, len);
}
zout.closeEntry();
} catch (Exception ex) {
ex.printStackTrace();
return null;
} finally {
try{zout.close();}catch(Exception ex){ex.printStackTrace();}
try{fis.close();}catch(Exception ex){ex.printStackTrace();}
}
return zipFile.getAbsolutePath();
}
Most of the examples have wrong exception handling.
public static byte[] gzipBytes(byte[] payload) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(baos)) {
gzip.write(payload);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
// note: toByteArray should be called after try-with-resources, not inside
return baos.toByteArray();
}
public static byte[] gunzipBytes(byte[] gzPayload) {
ByteArrayInputStream bais = new ByteArrayInputStream(gzPayload);
try (GZIPInputStream gzip = new GZIPInputStream(bais)) {
// java 9+ required for this method
return gzip.readAllBytes();
} catch (IOException e) {
throw new UncheckedIOException("Error while unpacking gzip content", e);
}
}
Try with this code..
try {
String inputFileName = "test.txt"; //may use your file_Path
String zipFileName = "compressed.zip";
//Create input and output streams
FileInputStream inStream = new FileInputStream(inputFileName);
ZipOutputStream outStream = new ZipOutputStream(new FileOutputStream(zipFileName));
// Add a zip entry to the output stream
outStream.putNextEntry(new ZipEntry(inputFileName));
byte[] buffer = new byte[1024];
int bytesRead;
//Each chunk of data read from the input stream
//is written to the output stream
while ((bytesRead = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, bytesRead);
}
//Close zip entry and file streams
outStream.closeEntry();
outStream.close();
inStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Also may be helpful this one..
http://www.java-samples.com/java/zip_files_in_a_folder_using_java.htm