2012-11-17 32 views
5

Tôi đang sử dụng một thư viện bytecode được gọi là ASM để thay đổi các tệp lớp, sau đó tôi muốn viết từng tệp lớp vào một tệp jar hơn là một thư mục chứa các tệp lớp. Tôi làm điều này bằng cách chạy mã này:Invalid Entry Compressed Size

Vấn đề của tôi xảy ra khi một ZipException là ném vì không kích thước dự kiến, tức là

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

} 

Các ClassReader, ClassWriter (mỗi phần của thư viện), và FieldAdapter (làm bởi bản thân mình) chỉ cần bàn thờ mã, và để có được các byte của toàn bộ lớp tôi sử dụng cw.toByteArray(). Không có vấn đề gì đối với thao tác bytecode chính nó, nó chỉ là văn bản cho một tệp jar mới thông qua một JarOutputStream. Bất cứ ai biết làm thế nào để giải quyết vấn đề này?

+1

Những phương pháp ném ngoại lệ này? Bạn có thể đăng toàn bộ dấu vết ngăn xếp không? – ShyJ

Trả lời

8

Dòng vấn đề là thế này:

JarEntry je = new JarEntry(jarEntry); 

vì nó cũng sẽ sao chép các kích thước nén.

Trừ khi bạn quan tâm đến việc bảo tồn các lĩnh vực khác ngoài tên, bạn nên sử dụng this constructor và chỉ cung cấp tên tập tin, như thế này:

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

Kích thước nén sẽ được sau đó tự động tính toán.

+0

Đã làm việc 100% cảm ơn bạn –

4

làm theo cách này, nó sẽ không sao chép Thuộc tính Jar và thông tin meta khác. Sự cố xảy ra khi tệp jar/zip được sửa đổi sau khi được đóng gói ban đầu.

Bạn có thể làm điều này:

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

này sẽ làm cho kích thước của entry được tính toán lại và bạn sẽ được sao chép tất cả các thuộc tính khác từ bản gốc jarEntry