JarEntry.getSize() is returning -1 when the jar files is opened as InputStream from URL
Asked Answered
A

3

6

I am trying to read file from the JarInputStream and the size of file is returning -1. I am accessing Jar file from the URL as a inputStream.

        URLConnection con = url.openConnection();

        JarInputStream jis = new JarInputStream(con.getInputStream());
        JarEntry je = null;

        while ((je = jis.getNextJarEntry()) != null) {
            htSizes.put(je.getName(), new Integer((int) je.getSize()));
            if (je.isDirectory()) {
                continue;
            }
            int size = (int) je.getSize();
            // -1 means unknown size.
            if (size == -1) {
                size = ((Integer) htSizes.get(je.getName())).intValue();
            }
            byte[] b = new byte[(int) size];
            int rb = 0;
            int chunk = 0;
            while (((int) size - rb) > 0) {
                chunk = jis.read(b, rb, (int) size - rb);
                if (chunk == -1) {
                    break;
                }
                rb += chunk;
            }
            // add to internal resource hashtable
            htJarContents.put(je.getName(), baos.toByteArray());
        }
Appetite answered 18/1, 2012 at 11:59 Comment(0)
P
4

This is documented behavior. Javadoc says that getSize() ...

"Returns the uncompressed size of the entry data, or -1 if not known."

Obviously, this is a situation where the actual size of the uncompressed data is not known. Your application will just have to deal with this.


FOLLOWUP

You commented on another answer:

Though we have the total content size, i think with out having the individual file size we can't read the files.

If you don't have the size, you can still read the file and buffer it using a ByteArrayOutputStream, then call toByteArray() to extract the buffered bytes as a byte[]. In fact, given that (per Tom Hawtin's comment) the reported size could be incorrect, you possibly should do this anyway, and just treat the reported size as a hint ... and just use it as the ByteArrayOutputStream's initial capacity.

(Incidentally, the code in your question looks like it might have been intended to work that way ... judging from the 2nd to last line. The problem is that the rest of the code doesn't use the baos object.)

Paz answered 18/1, 2012 at 12:7 Comment(3)
Even if it is known, it might be a lie.Ingrain
I am trying to read the file and buffer it, Now I am facing another issue. The original size of the JarEntry and the buffered size is differed and am getting more bytes than the expected. I even checked and confirmed jar file is not corrupted.Appetite
@ReshmaDonthireddy - this is what Tom Hawtin means when he says that the size might be a lie.Paz
P
4
byte[] classbytes = null;
JarInputStream jis = new JarInputStream(is);
JarEntry je = null;
String jename = null;
while((je = jis.getNextJarEntry()) != null){
    jename = je.getName();
    if(je.getSize() != -1){
        classbytes = new byte[(int)je.getSize()];
        int len = (int) je.getSize();
        int offset = 0;
        while (offset != len)
            offset += jis.read(classbytes, offset, len - offset);
        classes.put(jename, classbytes);
    } else {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while(true){
            int qwe = jis.read();
            if(qwe == -1) break;
            baos.write(qwe);
        }
        classbytes = baos.toByteArray();
        classes.put(jename, classbytes);
    }
}
Pendant answered 24/6, 2012 at 9:13 Comment(1)
This actually answers the question. When the size is unknown, it reads the input stream into a temporary byte array output stream until the end of the input stream, then returns the corresponding byte array. Thanks, this worked for me!Eddings
C
1

This might be because the server that's serving that url does not provide a contentLenght. this is similar to when you sometimes download a file with your browser and it says 33Kb/?? downloaded (as opposed to 33Kb/2049Kb downloaded).

To quickly check if that's the case you can do something like this:

URL url = new URL(yourUrl);
conn = url.openConnection();
size = conn.getContentLength();
if(size < 0) {
    System.out.println("Could not determine file size.");
} else {
    System.out.println(yourUrl + "\nSize: " + size);
}
Caitlyncaitrin answered 18/1, 2012 at 12:7 Comment(3)
Thanks Andrei Bodnarescu. Content length is fine. I am able to access the file names also. Issue is with finding out the size of the individual file. I need to read those files from inputstream and have to put in a hashtable.Appetite
Well if content lenght returns the correct value, can't you use that to determine it (like, before opening the stream)?Caitlyncaitrin
Though we have the total content size, i think with out having the individual file size we can't read the files.Appetite

© 2022 - 2024 — McMap. All rights reserved.