2012-03-03 79 views
1

我正在使用以下方法从jar条目(仅包含类文件)中读取字节。 jar里面没有jar文件。使用JarInputStream读取字节时调用defineClass时的ClassFormatError读取方法

private List<byte[]> readFromJarFile(File cp) 
{ 
    List<byte[]> cbytes = new ArrayList<byte[]>(); 
    try 
    { 
     java.util.jar.JarInputStream jin = new java.util.jar.JarInputStream(new java.io.FileInputStream(cp)); 
     java.util.jar.JarEntry je = jin.getNextJarEntry(); 
     while (je != null) 
     { 
      if (!je.isDirectory() && je.toString().endsWith(".class")) 
      { 
       //assume class file size < Integer.MAX_VALUE 
       System.out.printf("readFromJarFile: jar entry name %s ...%n",je.toString()); 
       byte[] cbyte = new byte[(int) je.getSize()]; 
       jin.read(cbyte,0,(int) je.getSize()); 
       cbytes.add(cbyte); 
      } 
      je = jin.getNextJarEntry(); 
     } 
    } 
    catch (java.io.IOException ie) 
    { 
     ie.printStackTrace(); 
    } 

    return cbytes; 
} 

现在,当我打电话的defineClass字节数组从以下异常上述方法返回被抛出。

java.lang.ClassFormatError: Unknown constant tag 0 in class file <Unknown> 
at java.lang.ClassLoader.defineClass1(Native Method) 
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) 
at java.lang.ClassLoader.defineClass(ClassLoader.java:615) 
at java.lang.ClassLoader.defineClass(ClassLoader.java:465) 
at san.tool.JPAEntityProcessor$JPAClassLoader.loadClass(JPAEntityProcessor.java:34) 
at san.tool.JPAEntityProcessor.processJPAEntities(JPAEntityProcessor.java:49) 
at san.tool.JPAEntityProcessorTest.testWithJarFile(JPAEntityProcessorTest.java:40) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at 

我搜索了这个网站和互联网上的所有其他论坛,但无法找到答案。我期待着来自这里的成员的一些见解。

感谢和问候 Santanu

+0

有趣。你可以用这样的jar文件发布带有基本测试用例的zip吗? – 2012-03-03 16:40:14

+0

好的,我将发布我的代码与jar文件的zip。但在这里很新,所以不知道如何发布zip文件。 – Santanu 2012-03-17 20:58:36

回答

4
jin.read(cbyte,0,(int) je.getSize()); 

它不能保证read方法将读取je.getSize()字节到缓冲器。而是返回实际读取的字节数。您需要将读取尝试封装到循环中并读取,直到填充缓冲区。

事情是这样的:

int len = (int) je.getSize(); 
int offset = 0; 
int read; 
while ((read = jin.read(cbyte, offset, len - offset)) > 0) { 
    offset += read; 
} 

UPD一年,我意识到以后,我原来的例子会阅读整个流之后卡住。后来的“固定”版本实际上不会进入循环。所以,这里是简短的,正确的和经过测试的版本。

+0

如果我的读取缓冲区大小小于条目(或文件)的大小,我假设需要while循环。我在哪里假设这个错误?为什么这个循环是必需的,即使条目大小和我的读取缓冲区大小相同? – Santanu 2012-03-06 18:51:27

+1

不,在我的例子中,我们用接收数据的部分填充缓冲区,假设缓冲区足够大以容纳所有数据。如果缓冲区已满,但数据仍可用,它将永远循环。它是['read']的一般合同(http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#read%28byte [],%20int,%20int%29 ) 方法。您请求它填充缓冲区,并使用当前可用数据填充缓冲区,但不会更多。 – Mersenne 2012-03-06 20:53:38

0

我有同样的问题,实际上这样做是正确的方法:

int read = 0; 
int len = (int) je.getSize(); 
int offset = 0; 
do { 
    read = jin.read(cbyte, offset, len - offset); 
    offset += read; 
} while (read > 0); 

这我测试和工程。请注意,在上面的答案中,它将永远不会进入循环,因为read已初始化为零。

相关问题