Java 为什么InputStreamReader在从jar读取时抛出NPE?

Java 为什么InputStreamReader在从jar读取时抛出NPE?,java,jar,stream,io,inputstream,Java,Jar,Stream,Io,Inputstream,我试图使用streams在已知目录中迭代类文件。最终目标是获取特定包中存在的所有类的类名,然后在运行时加载这些类,并使用反射来获取所有静态常量的名称和值。当我在我的机器上从源代码运行程序时,这是可行的,但当我将其作为jar运行时,BufferedReader会从ready()和readLine()抛出一个NPE。以下是代码(为了简洁起见,省略了错误处理和最佳实践): 来自reader.ready()的堆栈跟踪: 来自reader.readLine()的堆栈跟踪: 单步执行将显示以下InputSt

我试图使用streams在已知目录中迭代类文件。最终目标是获取特定包中存在的所有类的类名,然后在运行时加载这些类,并使用反射来获取所有静态常量的名称和值。当我在我的机器上从源代码运行程序时,这是可行的,但当我将其作为jar运行时,
BufferedReader
会从
ready()
readLine()
抛出一个NPE。以下是代码(为了简洁起见,省略了错误处理和最佳实践):

来自
reader.ready()的堆栈跟踪:

来自
reader.readLine()的堆栈跟踪:

单步执行将显示以下
InputStream
实现:

  • 源代码:
    java.io.ByteArrayInputStream
  • 来自jar:
    sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream
进一步查看
JarURLInputStream
我发现
中继承的(来自
FilterInputStream
)字段
InputStream
null
,这导致产生NPE

不幸的是,这是我在调试器中所能达到的深度


关于如何正确地做到这一点有什么想法吗?我错过了什么或做错了什么?谢谢大家!

文件夹不会返回包含所有文件列表或其他内容的
InputStream
。用于以编程方式提取JAR。你可以找到一个例子。作为参考,这里有一个稍微修改的相关性摘录:

public static List<String> getClassNamesInPackage(String jarName, String packageName) throws IOException {
    JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
    packageName = packageName.replace(".", "/");
    List<String> classes = new ArrayList<String>();

    try {
        for (JarEntry jarEntry; (jarEntry = jarFile.getNextJarEntry()) != null;) {
            if ((jarEntry.getName().startsWith(packageName)) && (jarEntry.getName().endsWith(".class"))) {
                classes.add(jarEntry.getName().replace("/", "."));
            }
        }
    } finally {
        jarFile.close();
    }

    return classes;
}
publicstaticlist getClassNamesInPackage(stringjarname,stringpackagename)抛出IOException{
JarInputStream jarFile=newjarinputstream(newfileinputstream(jarName));
packageName=packageName.replace(“.”,“/”);
列表类=新的ArrayList();
试一试{
for(JarEntry-JarEntry;(JarEntry=jarFile.getNextJarEntry())!=null;){
if((jarEntry.getName().startsWith(packageName))&&(jarEntry.getName().endsWith(“.class”)){
add(jarEntry.getName().replace(“/”,“);
}
}
}最后{
jarFile.close();
}
返回类;
}

总而言之,您试图获取文件夹的
InputStream
,而不是文件,对吗?是否可能是“getClass().getClassLoader().getResourceAsStream(strPackage)”;“返回空值?”@BalusC:是的。最初的实现只是为
strPackage
目录创建了一个
新文件
,然后使用
listFiles()
获取其中的类。我正在对其进行重构,以使用流而不是
文件
对象,这样我们就可以支持从jar执行。@JustinKSU:不,正如您所看到的,我提供了由
getResourceAsStream
返回的运行时实现。文件夹不会返回包含所有文件列表或其他内容的
InputStream
。使用
JarInputStream
以编程方式提取JAR。感谢您的回复,我不知道
JarInputStream
类。这可能很好,但我关心的是jar名称的需要——为什么没有解决方案可以保证我从jar加载而不是从本地文件系统加载的事实是透明的?我还没试过,但我会告诉你我发现了什么。它确实存在,但不是你想要的方式。只有通过名称知道类路径上的项,才能引用它们。然后类加载器透明地处理加载:它可能从文件、JAR、网络套接字等加载。没有通用方法列出这些项。
java.lang.NullPointerException
    at java.io.FilterInputStream.available(FilterInputStream.java:142)
    at sun.nio.cs.StreamDecoder.inReady(StreamDecoder.java:343)
    at sun.nio.cs.StreamDecoder.implReady(StreamDecoder.java:351)
    at sun.nio.cs.StreamDecoder.ready(StreamDecoder.java:165)
    at java.io.InputStreamReader.ready(InputStreamReader.java:178)
    at java.io.BufferedReader.ready(BufferedReader.java:436)
java.lang.NullPointerException
    at java.io.FilterInputStream.read(FilterInputStream.java:116)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
public static List<String> getClassNamesInPackage(String jarName, String packageName) throws IOException {
    JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
    packageName = packageName.replace(".", "/");
    List<String> classes = new ArrayList<String>();

    try {
        for (JarEntry jarEntry; (jarEntry = jarFile.getNextJarEntry()) != null;) {
            if ((jarEntry.getName().startsWith(packageName)) && (jarEntry.getName().endsWith(".class"))) {
                classes.add(jarEntry.getName().replace("/", "."));
            }
        }
    } finally {
        jarFile.close();
    }

    return classes;
}