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

巧了我就是萌 提交于 2019-12-19 18:51:54

问题


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());
        }

回答1:


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




回答2:


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);
    }
}



回答3:


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);
}


来源:https://stackoverflow.com/questions/8909743/jarentry-getsize-is-returning-1-when-the-jar-files-is-opened-as-inputstream-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!