I am trying to Zip file using ZipOutputStream but it's throwing StringIndexOutOfBoundsException while passing a FileOutPutStream object.
The code was working fine when I ran it as a separate java class but when I integrated it with my project, it's throwing the exception.
I used this code:
byte[] buffer = new byte[1024];
try{
FileOutputStream fos = new FileOutputStream("C:\\Report.zip");
//error throwing at this point (java.lang.StringIndexOutOfBoundsException)
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
FileInputStream in = new FileInputStream("C:\\Report.xls");
zos.putNextEntry(new ZipEntry("Report.xls"));
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
zos.closeEntry();
zos.close();
}catch(IOException ex){
Log.report.debug(ex.toString());
}
Related
I am attempting to zip files from one folder into a zip folder located in another directory. The problem is that the zip folder is becoming corrupted. What is causing this and how do I fix it.
FileInputStream fis = null;
FileOutputStream fos = new FileOutputStream("C:/Users/admin/Documents/files.zip");
ZipOutputStream zos = new ZipOutputStream(fos);
File folder = new File("C:/Users/admin/Documents/filestozip");
for(File file:folder.listFiles())
{
fis = new FileInputStream(file);
ZipEntry entry = new ZipEntry(file.getAbsolutePath());
zos.putNextEntry(entry);
byte[] bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0)
{
zos.write(bytes, 0, length);
}
zos.closeEntry();
fis.close();
}
zos.flush();
zos.finish();
zos.close();
fos.flush();
fos.close();
I am working on reading a file and write same file, but the problem is the downloaded file is 2kb larger than input original file.
Some piece of code
#Override
public void run() {
try {
BufferedInputStream bis;
ArrayList<byte[]> al =new ArrayList<byte[]>();
File file = new File(Environment.getExternalStorageDirectory(), "test.mp3");
byte[] bytes = new byte[2048];
bis = new BufferedInputStream(new FileInputStream(file));
OutputStream os = socket.getOutputStream();
int read ;
int fileSize = (int) file.length();
int readlen=1024;
while (fileSize>0) {
if(fileSize<1024){
readlen=fileSize;
System.out.println("Hello.........");
}
bytes=new byte[readlen];
read = bis.read(bytes, 0, readlen);
fileSize-=read;
al.add(bytes);
}
ObjectOutputStream out1 = new ObjectOutputStream(new FileOutputStream(Environment.getExternalStorageDirectory()+"/newfile.mp3"));
for(int ii=1;ii<al.size();ii++){
out1.write(al.get(ii));
// out1.flush();
}
out1.close();
File file1 = new File(Environment.getExternalStorageDirectory(), "newfile.mp3");
Don't use an ObjectOutputStream. Just use the FileOutputStream, or a BufferedOutputStream wrapped around it.
The correct way to copy streams in Java is as follows:
byte[] buffer = new byte[8192]; // or more, or even less, anything > 0
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
out.close();
Note that you don't need a buffer the size of the input, and you don't need to read the entire input before writing any of the output.
Wish I had $1 for every time I've posted this.
I think you should use ByteArrayOutputStream not an ObjectOutputStream.
I belive this is not a raw code, but the parts of the code, placed in different procedures, otherwise it is meaningless.
For example, in case you want to stream some data from a file, process this data, and then write the data to another file.
BufferedInputStream bis = null;
ByteArrayOutputStream al = new ByteArrayOutputStream();
FileOutputStream out1 = null;
byte[] bytes;
try {
File file = new File("testfrom.mp3");
bis = new BufferedInputStream(new FileInputStream(file));
int fileSize = (int) file.length();
int readLen = 1024;
bytes = new byte[readLen];
while (fileSize > 0) {
if (fileSize < readLen) {
readLen = fileSize;
}
bis.read(bytes, 0, readLen);
al.write(bytes, 0, readLen);
fileSize -= readLen;
}
bis.close();
} catch (IOException e){
e.printStackTrace();
}
//proceed the data from al here
//...
//finish to proceed
try {
out1 = new FileOutputStream("testto.mp3");
al.writeTo(out1);
out1.close();
} catch (IOException e){
e.printStackTrace();
}
Don't forget to use try-catch directives where it needed
http://codeinventions.blogspot.ru/2014/08/creating-file-from-bytearrayoutputstrea.html
I have the following java method which I'm trying to use to create a zip file, which has an existing file written into it (the zip file has the same name, just with the .log extension replaced with .zip) . The zip file is created successfully, however the file is not inside it when it completes.
Here is my code:
private static void zipFile(File fileToZip) {
final int bufferSize = 2048;
File zipFile = new File(fileToZip.getAbsolutePath().replaceAll(".log", ".zip"));
try (FileOutputStream fos = new FileOutputStream(zipFile.getAbsolutePath());
FileInputStream fis = new FileInputStream(fileToZip);
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
BufferedInputStream origin = new BufferedInputStream(fis, bufferSize)) {
ZipEntry ze = new ZipEntry(fileToZip.getAbsolutePath());
zos.putNextEntry(ze);
byte[] data = new byte[bufferSize];
int count;
while ((count = origin.read(data, 0, bufferSize)) != -1) {
LOGGER.info("WRITING!!!");
zos.write(data, 0, count);
}
zos.closeEntry();
} catch (IOException e) {
LOGGER.error("Error: ", e);
}
}
Any ideas? :)
Change
ZipEntry ze = new ZipEntry(fileToZip.getAbsolutePath());
to
ZipEntry ze = new ZipEntry(fileToZip.getName());
I was trying to flush data in a file in my local machine to response. But at some point I get an IndexOutOfBoundsException.
FileInputStream inputStream = new FileInputStream(downloadFile);
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer, 0, 4096)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
The above code is what I was trying. The downloadFile path given is correct and it works till the while loop. But then the IndexOutOfBoundsException occurs. I tried it with inputStream.read(buffer) but that didn't work.
Give code is working perfectlly; since there is no information is given regarding the response object I have modify the OutputStream to FileOutputStream; just to test.
Below code segment is working perfectly.
public class Test
{
public static void main(String args[]) throws IOException
{
FileInputStream inputStream = new FileInputStream("C:\\readme.txt");
FileOutputStream outputStream = new FileOutputStream("D:\\readme1.txt");
//OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer, 0, 4096)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
}
}
Consider the code example that put a single file test_file.pdf into zip archive test.zip and then read this archive:
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class Main {
public static void main(String[] args) {
File infile = new File("test_file.pdf");
try (
FileInputStream fis = new FileInputStream(infile);
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("test.zip"));
) {
int bytesRead;
byte[] buffer = new byte[1024];
ZipEntry entry = new ZipEntry("data");
entry.setSize(infile.length());
zos.putNextEntry(entry);
while ((bytesRead = fis.read(buffer)) >= 0)
{
zos.write(buffer, 0, bytesRead);
}
zos.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
try (
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(
new FileInputStream(new File("test.zip"))));
) {
ZipEntry entry = zis.getNextEntry();
System.out.println("Entry size: " + entry.getSize());
zis.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output:
Entry size: -1
But if create uncompressed zip archive (method ZipEntry.STORED), getSize() returns correct size:
import java.io.*;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class Main {
public static void main(String[] args) {
File infile = new File("test_file.pdf");
try (
FileInputStream fis = new FileInputStream(infile);
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("test.zip"));
) {
int bytesRead;
byte[] buffer = new byte[1024];
CRC32 crc = new CRC32();
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile));
) {
crc.reset();
while ((bytesRead = bis.read(buffer)) != -1) {
crc.update(buffer, 0, bytesRead);
}
}
ZipEntry entry = new ZipEntry("data");
entry.setMethod(ZipEntry.STORED);
entry.setCompressedSize(infile.length());
entry.setSize(infile.length());
entry.setCrc(crc.getValue());
zos.putNextEntry(entry);
while ((bytesRead = fis.read(buffer)) >= 0)
{
zos.write(buffer, 0, bytesRead);
}
zos.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
try (
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(
new FileInputStream(new File("test.zip"))));
) {
ZipEntry entry = zis.getNextEntry();
System.out.println("Entry size: " + entry.getSize());
zis.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output (for example but correct):
Entry size: 9223192
Compressed zip archives with correct entry.getSize() exists (e.g. zip archives by Ark program).
So question: how to create compressed (ZipEntry.DEFLATED or another if exists) zip archive that returns correct size of the entry using only the standard libraries?
I tried this recommendation but it also does not work:
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class Main {
public static void main(String[] args) {
File infile = new File("test_file.pdf");
try (
FileInputStream fis = new FileInputStream(infile);
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("test.zip"));
) {
int bytesRead;
byte[] buffer = new byte[1024];
ZipEntry entry = new ZipEntry("data");
entry.setSize(infile.length());
zos.putNextEntry(entry);
while ((bytesRead = fis.read(buffer)) >= 0)
{
zos.write(buffer, 0, bytesRead);
}
zos.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
try (
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(
new FileInputStream(new File("test.zip"))));
) {
ZipEntry entry = zis.getNextEntry();
byte[] buffer = new byte[1];
zis.read(buffer);
System.out.println("Entry size: " + entry.getSize());
zis.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output:
Entry size: -1
You can only set the uncompressed size if you also set the CRC and compressed size as well. Since these information are stored before in a header before the actual data and ZipOutputStream can’t rewind arbitrary OutputStreams, it can’t calculate these values while writing and store them afterwards (but it will calculate them for verifying the provided values).
Here is a solution for calculating the values in one pass before the writing. It utilizes the fact that you can rewind a stream if it is backed by a file.
public static void main(String[] args) throws IOException {
File infile = new File("test_file.pdf");
File outfile = new File("test.zip");
try (FileInputStream fis = new FileInputStream(infile);
FileOutputStream fos = new FileOutputStream(outfile);
ZipOutputStream zos = new ZipOutputStream(fos) ) {
byte[] buffer = new byte[1024];
ZipEntry entry = new ZipEntry("data");
precalc(entry, fis.getChannel());
zos.putNextEntry(entry);
for(int bytesRead; (bytesRead = fis.read(buffer)) >= 0; )
zos.write(buffer, 0, bytesRead);
zos.closeEntry();
}
try(FileInputStream fin = new FileInputStream(outfile);
ZipInputStream zis = new ZipInputStream(fin) ) {
ZipEntry entry = zis.getNextEntry();
System.out.println("Entry size: " + entry.getSize());
System.out.println("Compressed size: " + entry.getCompressedSize());
System.out.println("CRC: " + entry.getCrc());
zis.closeEntry();
}
}
private static void precalc(ZipEntry entry, FileChannel fch) throws IOException {
long uncompressed = fch.size();
int method = entry.getMethod();
CRC32 crc = new CRC32();
Deflater def;
byte[] drain;
if(method != ZipEntry.STORED) {
def = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
drain = new byte[1024];
}
else {
def = null;
drain = null;
}
ByteBuffer buf = ByteBuffer.allocate((int)Math.min(uncompressed, 4096));
for(int bytesRead; (bytesRead = fch.read(buf)) != -1; buf.clear()) {
crc.update(buf.array(), buf.arrayOffset(), bytesRead);
if(def!=null) {
def.setInput(buf.array(), buf.arrayOffset(), bytesRead);
while(!def.needsInput()) def.deflate(drain, 0, drain.length);
}
}
entry.setSize(uncompressed);
if(def!=null) {
def.finish();
while(!def.finished()) def.deflate(drain, 0, drain.length);
entry.setCompressedSize(def.getBytesWritten());
}
entry.setCrc(crc.getValue());
fch.position(0);
}
It handles both, uncompressed and compressed entries, but unfortunately, only with the default compression level as ZipOutputStream has no method for querying the current level. So if you change the compression level you have to keep the precalc code in sync. Alternatively, you could move the logic into a subclass of ZipOutputStream and use the same Deflater so it will automatically have the same configuration.
A solution working with arbitrary source input streams would require buffering of the entire entry data.
A simple and elegant workaround is to write the ZipEntry to a temporary ZipOutputStream first. This is what the updateEntry method of the following code does. When the method has been called, the ZipEntry knows the size, compressed size and CRC, without having to calculate them explicitly. When it is written to the target ZipOutputStream, it will correctly write the values.
Original answer:
dirty but fast
public static void main(String[] args) throws IOException
{
FileInputStream fis = new FileInputStream( "source.txt" );
FileOutputStream fos = new FileOutputStream( "result.zip" );
ZipOutputStream zos = new ZipOutputStream( fos );
byte[] buf = new byte[fis.available()];
fis.read(buf);
ZipEntry e = new ZipEntry( "source.txt" );
updateEntry(e, buf);
zos.putNextEntry(e);
zos.write(buf);
zos.closeEntry();
zos.close();
}
private static void updateEntry(ZipEntry entry, byte[] buffer) throws IOException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream( bos );
zos.putNextEntry(entry);
zos.write(buffer);
zos.closeEntry();
zos.close();
bos.close();
}