Java 使用JarInputStream读取方法读取字节调用defineClass时发生ClassFormatError

Java 使用JarInputStream读取方法读取字节调用defineClass时发生ClassFormatError,java,classloader,Java,Classloader,我使用以下方法从jar条目(仅包含类文件)读取字节。jar中没有jar文件 private List<byte[]> readFromJarFile(File cp) { List<byte[]> cbytes = new ArrayList<byte[]>(); try { java.util.jar.JarInputStream jin = new java.util.jar.JarInputStream(new

我使用以下方法从jar条目(仅包含类文件)读取字节。jar中没有jar文件

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;
}
private List readFromJarFile(文件cp)
{
List cbytes=new ArrayList();
尝试
{
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)
{
如果(!je.isDirectory()&&je.toString().endsWith(“.class”))
{
//假设类文件大小
现在,当我使用从上述方法返回的字节数组调用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 
java.lang.ClassFormatError:类文件中未知的常量标记0
位于java.lang.ClassLoader.defineClass1(本机方法)
位于java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
位于java.lang.ClassLoader.defineClass(ClassLoader.java:615)
位于java.lang.ClassLoader.defineClass(ClassLoader.java:465)
位于san.tool.JPAEntityProcessor$JPAClassLoader.loadClass(JPAEntityProcessor.java:34)
位于san.tool.JPAEntityProcessor.processJPAEntities(JPAEntityProcessor.java:49)
位于san.tool.JPAEntityProcessorTest.testWithJarFile(JPAEntityProcessorTest.java:40)
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
在
我搜索了这个网站和互联网上的所有其他论坛,但没有找到答案。我期待着在座各位的一些见解

谢谢和问候 桑塔努

不能保证
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一年后,我意识到,在阅读了整个流之后,我原来的示例将被卡住。后来的“固定”版本实际上不会进入循环。所以,这里有一个简短、正确且经过测试的版本

不能保证
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一年后,我意识到,在阅读了整个流之后,我原来的示例将被卡住。后来的“固定”版本实际上不会进入循环。因此,这里有一个简短、正确且经过测试的版本。

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

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
已初始化为零。

我遇到了相同的问题,实际上正确的方法是:

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
被初始化为零。

。你可以发布一个带有这样一个jar文件的基本测试用例的zip吗?好的,我将在发布jar文件的同时发布我的代码的zip。但是我是新来的,所以不知道如何发布zip文件。很有趣。你可以发布一个带有这样一个jar文件的基本测试用例的zip吗?好的,我将在发布jar文件的同时发布我的代码的zip。但是我在这里是新手,所以不知道如何发布zip文件。我假设如果我的读取缓冲区大小小于条目(或文件)的大小,则需要while循环。我在哪里犯了这样的错误?为什么即使条目大小和我的读取缓冲区大小相同,也需要此循环?不,在我的示例中,我们使用部分接收数据填充缓冲区,假设缓冲区足够大,可以容纳所有数据。若缓冲区被填满,但数据仍然可用,它将永远循环。这是方法的总合同。您请求它填充缓冲区,它会用当前可用数据填充缓冲区,但不会更多。我假设如果我的读取缓冲区大小小于条目(或文件)的大小,则需要while循环。我在哪里犯了这样的错误?为什么即使条目大小和我的读取缓冲区大小相同,也需要此循环?不,在我的示例中,我们使用部分接收数据填充缓冲区,假设缓冲区足够大,可以容纳所有数据。若缓冲区被填满,但数据仍然可用,它将永远循环。这是方法的总合同。您请求它填充缓冲区,它用当前可用数据填充缓冲区,但不再填充。