views:

63

answers:

4

The background
Currently, I try to get a zip-file through a HTTP-servlet with a HTTP-request. The received zip-file contains three different files. These files contain information I want to filter out and doing this from the source is not an option (that's just how it is, though I am aware it would be much better).

Because I cant filter out some information in the file from the source, where the file is build from the beginning, my solution is to decompress the file, read these three files as strings and then filter them. In the end "rebuild" all as a "zipfile" (inputStream) and return the inputStream.

The problem
Currently, I've made a class to handle the decompression and filtering of the file. In the end I just want to return the new inputStream containing the zip-file and the three files inside.

I've come as far as get the content from the HTTP entity into a inputStream, decompress this inputStream and get the three files as three strings. To just try to see if this work, I currently don't want to do more than just decompress them and just close the inputStream and return it.. This does however cause an exception when I return the inputStream:

 java.io.IOException: Attempted read on closed stream.

This is because the inputStream is used outside the function I present below. As I close the zipInputStream, I probably also closes the inputStream for further work.

The current code

public InputStream convertInputStream(HttpEntity entity)
{
    InputStream inputStream = null;
    try
    {
        inputStream = entity.getContent();
    }
    catch (IOException e11)
    {

    }

    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    Vector <String>entryVector = new Vector<String>();
    ZipEntry entry;
    try
    {
        String entryValue;
        while((entry = zipInputStream.getNextEntry()) != null)
        {           
            System.out.println("Unzipping file: " + entry.getName() + "...");
            byte [] buf = new byte[(int) entry.getSize()];
            zipInputStream.read(buf);
            entryValue = new String(buf);
            entryVector.add(entryValue);
            zipInputStream.closeEntry();
        }
    }
    catch(IOException e)
    {
        System.out.println("error in getting next entry.");
    }
    finally
    {
        try 
        {
            zipInputStream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        System.out.println("Unzipping done!");
    }
    return inputStream;
}

I hope I manage to express this as clear as possible. I can still see that this is very confusing to understand when I can't show the whole solution outside this function.

A: 

I think that you need to read the contents on each entry and then call entry.closeEntry()

Maurice Perry
Yes. Code now updated, throws exception if trying to close the zipInputStream. If not, zip-file is corrupted.
Fredrik_jakob
+2  A: 

Where you print "unzipping file", you are not actually unzipping anything. If you want to do that, you need to read the content of the entry from the ZipInputStream using the read() function and write that to a file.

EDIT: You can try reading the (compressed) zip file from the input stream into a byte array. Then create a ByteArrayInputStream on that array and then wrap your ZipInputStream around that. Then you can safely close the input stream without closing the underlying stream.

Also, make sure that the file's content as String is actually useful. new String(byte[]) creates a string using the default encoding, so this may very well be useless.

Thomas Lötzer
Hm, of course, I missed that detail :P.But, this shouldn't corrupt the originating zip-file?
Fredrik_jakob
No, it should not, since the file is not altered.
Thomas Lötzer
Hmm. Okey. My problem is that I have an inputstream, where I want to change the content of some files inside the zip-file. After that, I want to compress it again and have it all as an inputstream again, which seems pretty off as you normal uses this kind of technique... I need it as an inputstream because of using the function IOUtils.copyLarge(inputStream, outputStream);. So the returned value after changed the content and compressed, should be an inputstream...
Fredrik_jakob
But this input stream has nothing to do with the input stream you are getting. You need to return a new input stream reading from your modified zip file.
Thomas Lötzer
Yes, I've manage to understand that too. The problem I see is to get a new inputstream... I've manage to get an ByteArrayInputStream so far :),
Fredrik_jakob
A: 

It sounds like you are trying to download the zip file whilst saving it simultaneously in binary and unzipped form. If that is the case, I would say download it first in binary form, then unzip it separately file disk afterwards.

If you don't want both, then you can choose which one you want to do, either by writing the plain stream to disk to get a binary zip file (no need to use a ZipInputStream); or by using a ZipInputStream and reading the data from each entry and writing it to disk (but don't use the plain input stream for writing to disk).

fd
A: 

So you're not "downloading" via network? By download you mean to decompress files from a zip-archive to your local hard-disk?

You can easily decompress a zip file with these methods:

    private static File unZipFile(File zipFileIn) throws Exception {
        ZipFile unZipFile = new ZipFile(zipFileIn);
        Enumeration<? extends ZipEntry> entries = unZipFile.entries();
        String topFile = null;
        while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
                if (entry.isDirectory()) {
                // Assume directories are stored parents first then children
                String extractFile = entry.getName();
                if (topFile == null) {
                    topFile = extractFile;
                }
                // This is not robust, just a quick solution
                (new File(entry.getName())).mkdir();
                continue;
            }
            copyInputStream(unZipFile.getInputStream(entry),new BufferedOutp    utStream(new FileOutputStream(entry.getName())));
        }
        unZipFile.close();
        File newFile = new File(zipFileIn.getParentFile().getAbsoluteFile(),topFile);
        return newFile;
    }

    private static final void copyInputStream(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int len;
            while((len = in.read(buffer)) >= 0)
            out.write(buffer, 0, len);
            in.close();
        out.close();
    }

The method returns you a File, which is the root of the decompressed files.

Perhaps it would be a good idea to ask your question more detailed on what you are trying to do. ATM everybody is guessing what you are trying to do instead of working on a solution.

Erik
Thank you very much. I'll update my question in a moment to try to explain the purpose of all this.
Fredrik_jakob