【问题标题】:Invalid Entry Compressed Size无效的条目压缩大小
【发布时间】:2012-11-17 23:07:10
【问题描述】:

我正在使用称为 ASM 的字节码库来更改类文件,然后我想将每个类文件写回 jar 文件而不是一个充满类文件的文件夹。我通过运行以下代码来做到这一点:

当 ZipException 因为不是预期的大小而被抛出时,就会出现我的问题,即

java.util.zip.ZipException: invalid entry compressed size (expected 695 but got 693 bytes)
    at java.util.zip.ZipOutputStream.closeEntry(Unknown Source)
    at org.steinburg.client.accessor.Accessor.accessJar(Accessor.java:64)
    at org.steinburg.client.accessor.Accessor.<init>(Accessor.java:41)
    at Loader.main(Loader.java:5)


package org.steinburg.client.accessor;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

public class Accessor {

private String input;
private File inFile;
private JarEntry jarEntry;
private JarFile jarFile;
private Enumeration<JarEntry> entries;
private InputStream is;

private String out;
private File outFile;
private FileOutputStream fos;
private JarOutputStream jos;

private byte[] bytes;

public Accessor(){
    try{
        input = new String("Input Jar.jar");
        inFile = new File(input);
        jarFile = new JarFile(inFile);
        entries = jarFile.entries();
        out = new String("Output Jar.jar");
        outFile = new File(out);
        fos = new FileOutputStream(outFile);
        jos = new JarOutputStream(fos);
        accessJar();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

protected final void accessJar(){
    try {
        while (entries.hasMoreElements()){
            jarEntry = entries.nextElement();
            is = jarFile.getInputStream(jarEntry);
            if (jarEntry.getName().endsWith(".class")){
                ClassReader cr = new ClassReader(is);
                ClassWriter cw = new ClassWriter(cr, 0);
                FieldAdapter fa = new FieldAdapter(cw);
                cr.accept(fa, 0);
                bytes = cw.toByteArray();
            } else {
                bytes = readBytes(is);
            }
            JarEntry je = new JarEntry(jarEntry);
            jos.putNextEntry(je);
            jos.write(bytes);
            jos.closeEntry();
        }
        jos.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

protected byte[] readBytes(InputStream inputStream){
    try{
        DataInputStream reader = new DataInputStream(inputStream);
        byte[] toReturn = new byte[reader.available()];
        reader.readFully(toReturn);
        reader.close();
        return toReturn;
    } catch (Exception e){
        e.printStackTrace();
        return null;
    }
}

}

ClassReader、ClassWriter(库的每个部分)和 FieldAdapter(我自己制作)只是祭坛代码,为了获取整个类的字节,我使用 cw.toByteArray()。字节码操作本身没有问题,只是通过 JarOutputStream 写入新的 jar 文件。有谁知道如何解决这个问题?

【问题讨论】:

  • 哪个方法会抛出这个异常?你能发布整个堆栈跟踪吗?

标签: java exception jar java-bytecode-asm


【解决方案1】:

有问题的行是这样的:

JarEntry je = new JarEntry(jarEntry);

因为它也会复制压缩后的大小。

除非您关心保留名称以外的其他字段,否则您应该使用 this constructor 并仅提供文件名,如下所示:

JarEntry je = new JarEntry(jarEntry.getName ());

然后会自动计算压缩后的大小。

【讨论】:

    【解决方案2】:

    这样做不会复制Jar Attributes和其他元信息。 该问题是jar/zip文件在初始打包后修改引起的。

    你可以这样做:

    JarEntry je = new JarEntry(jarEntry);
    je.setCompressedSize(-1);
    

    这将导致重新计算条目的大小,并且您将从原始 jarEntry 中复制所有其他属性

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-23
      相关资源
      最近更新 更多