例如,stream.read()假设com.google包存在于某个JAR(例如,Guava )中,此代码段会在该行上抛出NullPointerException(!).
ClassLoader classLoader = getClass().getClassLoader();
URL resource = classLoader.getResource("com/google");
InputStream stream = resource.openStream();
System.out.println(stream.toString()); // Fine -- stream is not null
stream.read(); // NPE inside FilterInputStream.read()!
Run Code Online (Sandbox Code Playgroud)
如果com/google与文件系统中的包而不是JAR交换,则代码段根本不会崩溃.事实上,它似乎读取该目录中的文件,由换行符分隔,但我无法想象在任何地方都指定了行为.
如果资源路径"com/google"指向"普通"资源文件或目录,是否有方法测试?
由于加载这些资源所涉及的协议处理程序的一些未指定的行为,这有点乱.在这种特殊情况下,有两个:sun.net.www.protocol.file.Handler和sun.net.www.protocol.jar.Handler,它们各自处理目录大小写略有不同.基于一些实验,这是他们每个人做的事情:
sun.net.www.protocol.file.Handler:
这样Handler做是打开a FileURLConnection,它完全按照你在面对目录时发现的那样做了.您可以检查它是否只是一个目录:
if (resource.getProtocol().equals("file")) {
return new File(resource.getPath()).isDirectory();
}
Run Code Online (Sandbox Code Playgroud)sun.net.www.protocol.jar.Handler:
Handler,在另一方面,会打开一个JarURLConnection最终使得其方式为ZipCoder.如果你看看那段代码,你会发现一些有趣的东西:将从本机JNI调用jzentry返回null,因为JAR zip文件实际上并没有包含一个名为的文件com/google,所以它返回null给包装的流它.但是,有一个解决方案.虽然ZipCoder找不到com/google,但它会发现com/google/(这是大多数ZIP接口工作的原因,出于某种原因).在那种情况下,jzentry将找到它,它将只返回一个空字节.
因此,通过所有这些随机特定于实现的行为,您可以通过首先尝试使用尾随访问资源/(无论如何都是URLClassLoader对目录的期望)来确定它是否是目录.如果ClassLoader.getResource()返回非null,则它是一个目录.如果没有,请尝试不使用尾部斜杠.如果它返回非null,则它是一个文件.如果它仍然返回null,那么它甚至不是现有资源.
有点hacky,但我认为没有更好的.我希望这有帮助!
| 归档时间: |
|
| 查看次数: |
5390 次 |
| 最近记录: |