I have this method that zips files from a List and another method that uses this for send it with mail through intent.
My problem is that when I send it two or three times the app crashes and shows me this.
E/StrictMode: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at java.io.FileOutputStream.<init>(FileOutputStream.java:89)
at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
at com.waffles.vatsandbats.VisaDatai.zip(VisaDatai.java:1172)
at com.waffles.vatsandbats.VisaDatai.sendZippedMail(VisaDatai.java:207)
at com.waffles.vatsandbats.VisaDatai.getFiles(VisaDatai.java:298)
at com.waffles.vatsandbats.VisaDatai$7$1.run(VisaDatai.java:1823)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5373)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)
The main problem (I think) is in this message
at com.waffles.vatsandbats.VisaDatai.zip(VisaDatai.java:1172)
That refers to this
in = new FileInputStream(files.get(i)
.getCanonicalFile());
Here's the method that creates the zip and that has the error code
public static File zip(List<File> files, String filename) {
File zipfile = new File(filename);
// Create a buffer for reading the files
FileInputStream in=null;
byte[] buf = new byte[1024];
try {
// create the ZIP file
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
zipfile));
// compress the files
for (int i = 0; i < files.size(); i++) {
in = new FileInputStream(files.get(i)
.getCanonicalFile());
// add ZIP entry to output stream
out.putNextEntry(new ZipEntry(files.get(i).getName()));
// 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();
return zipfile;
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
The list of files that I zip is several PrintedPdfDocuments with images and texts (this class has it owns disadvantages but Im lazy changing that right now)
I just can't find the problem. Maybe I need to change the method that zips. Any suggestions?
You should close your streams in a finally block to make sure they are closed properly even when an exception occurs.
Also using getCanonicalFile() creates a new file when you are creating your FileInputStream. You probably want:
in = new FileInputStream(files.get(i));
I solved it. I closed the FileInputStream inside the for loop. So every time it looped and opened the stream I also closed it.
I added a own try catch for the close block at finally just for being sure but when I took away the close section in the for loop it crashed.
Here's the working code
public File zip(List<File> files, String filename) {
File zipfile = new File(filename);
FileInputStream in=null;
ZipOutputStream out=null;
// Create a buffer for reading the files
byte[] buf = new byte[1024];
try {
// create the ZIP file
out = new ZipOutputStream(new FileOutputStream(
zipfile));
// compress the files
for (int i = 0; i < files.size(); i++) {
in = new FileInputStream(files.get(i));
// add ZIP entry to output stream
out.putNextEntry(new ZipEntry(files.get(i).getName()));
// transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
try {
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (IOException ex) {
ex.printStackTrace();
}finally {
try {
try {
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
out.closeEntry();
out.close();
}catch (Exception ex) {
ex.printStackTrace();
}
}
return zipfile;
}
Related
I developed an app where I am backing up and restoring app data. The backup data is stored in .zip format in phone directory. While restoring I am unzipping the file till here everything works fine. But, if the backup contain images as data, while restoring they are not opening in app and giving an error. The code written for unzipping file is written as
public void DBimport(String inFileName) {
opener= new DataBaseOpener(mApp);
final String outFileName = mContext.getDatabasePath(opener.getDatabaseName()).toString();
try {
File dbFile = new File(inFileName);
FileInputStream fis = new FileInputStream(dbFile);
ZipInputStream zipInputStream= new ZipInputStream(fis);
ZipEntry zipEntry= zipInputStream.getNextEntry();
while(zipEntry!=null) {
String fileName=zipEntry.getName();
File newFile= new File(outFileName/* + File.separator + fileName*/);
new File(newFile.getParent()).mkdirs();
// Open the empty db as the output stream
OutputStream output = new FileOutputStream(newFile);
// Transfer bytes from the input file to the output file
byte[] buffer = new byte[1024];
int length;
while ((length = zipInputStream.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
// Close the streams
output.flush();
output.close();
zipEntry=zipInputStream.getNextEntry();
}
zipInputStream.closeEntry();
fis.close();
Toast.makeText(mContext, "Restore Completed", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(mContext, "Unable to Restores. Retry", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
}
May I know where I am going wrong ? and how to resolve this issue. any suggestions will be helpful.
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...).
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();
}
}
}
}
I want to copy a file from network location into my local directory. I have written following code for this, but the problem is, it needs to have a file created first, and then the out stream writes the bytes stream into this file.
What i want is, the precondition to first create file locally should not be there. It should simply copy the network file into the mentioned directory directly, thats it! I'm kind of doing this for the first time.
try {
File srcFile = new File("//network//file//path//here");
File dstFileName = new File("//local//drive//file//path//here");
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(dstFileName);
byte[] buff = new byte[1024];
int length;
while ((length = in.read(buff)) > 0) {
out.write(buff, 0, length);
}
in.close();
out.close();
} catch (Exception ex) {
ex.printStackTrace();
}
You need to create the file, before you can write to it.
if(!dstFileName.exists()){
dstFileName.createNewFile();
}
If the the path does not exist, you can try to create it first with
dstFileName.getParentFile().mkdirs();
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.