Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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());
        }
like image 451
Reshma Donthireddy Avatar asked Jan 18 '12 11:01

Reshma Donthireddy


3 Answers

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.)

like image 54
Stephen C Avatar answered Sep 19 '22 12:09

Stephen C


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);
    }
}
like image 44
vlad20012 Avatar answered Sep 22 '22 12:09

vlad20012


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);
}
like image 23
Shivan Dragon Avatar answered Sep 18 '22 12:09

Shivan Dragon