2012-03-03 82 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已初始化爲零。

相關問題