【问题标题】:JarEntry.getSize() is returning -1 when the jar files is opened as InputStream from URL当 jar 文件从 URL 作为 InputStream 打开时,JarEntry.getSize() 返回 -1
【发布时间】:2012-02-13 03:34:57
【问题描述】:

我正在尝试从 JarInputStream 读取文件并且文件大小返回 -1。我正在从 URL 作为 inputStream 访问 Jar 文件。

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

【问题讨论】:

    标签: java jar inputstream


    【解决方案1】:

    这是记录在案的行为。 JavadocgetSize() ...

    “返回条目数据的未压缩大小,如果未知则返回 -1。”

    显然,这是未压缩数据的实际大小未知的情况。您的应用程序只需要处理这个问题。


    跟进

    您评论了另一个答案:

    虽然我们有总内容大小,但我认为如果没有单个文件大小,我们将无法读取文件。

    如果您没有大小,您仍然可以读取文件并使用ByteArrayOutputStream 对其进行缓冲,然后调用toByteArray() 将缓冲的字节提取为byte[]。事实上,鉴于(根据 Tom Hawtin 的评论)报告的大小可能不正确,您可能无论如何都应该这样做,并将报告的大小视为提示......并将其用作ByteArrayOutputStream的初始容量。

    (顺便说一句,您问题中的代码看起来可能是打算以这种方式工作的......从第 2 行到最后一行判断。问题是其余代码不使用 baos对象。)

    【讨论】:

    • 即使知道,也可能是谎言。
    • 我正在尝试读取文件并缓冲它,现在我面临另一个问题。 JarEntry 的原始大小和缓冲大小不同,并且获得的字节数比预期的要多。我什至检查并确认 jar 文件没有损坏。
    • @ReshmaDonthireddy - 这就是 Tom Hawtin 说尺寸可能是谎言时的意思。
    【解决方案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】:

    这可能是因为提供该 url 的服务器没有提供 contentLenght。这类似于您有时使用浏览器下载文件并显示 33Kb/??下载(相对于 33Kb/2049Kb 下载)。

    要快速检查是否是这种情况,您可以执行以下操作:

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

    【讨论】:

    • 感谢安德烈·博德纳雷斯库。内容长度很好。我也可以访问文件名。问题在于找出单个文件的大小。我需要从输入流中读取这些文件并且必须放入一个哈希表。
    • 如果内容长度返回正确的值,你不能用它来确定它(比如,在打开流之前)吗?
    • 虽然我们有总内容大小,但我认为如果没有单独的文件大小,我们将无法读取文件。
    猜你喜欢
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 2011-02-06
    • 1970-01-01
    • 2014-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多