我正在使用一个称为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文件。有谁知道如何解决这个问题?
答案 0 :(得分:9)
有问题的一行是:
JarEntry je = new JarEntry(jarEntry);
因为它也会复制压缩的大小。
除非您关心保留除名称之外的其他字段,否则应使用this constructor并仅提供文件名,如下所示:
JarEntry je = new JarEntry(jarEntry.getName ());
然后将自动计算压缩大小。
答案 1 :(得分:5)
这样做它不会复制Jar属性和其他元信息。 在最初打包jar / zip文件后修改jar / zip文件会导致此问题。
你可以这样做:
JarEntry je = new JarEntry(jarEntry);
je.setCompressedSize(-1);
这将导致重新计算条目的大小,并且您将复制原始jarEntry中的所有其他属性