有没有办法判断类路径资源是文件还是目录?

Tav*_*nes 9 java classpath

例如,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"指向"普通"资源文件或目录,是否有方法测试?

Adr*_*scu 9

由于加载这些资源所涉及的协议处理程序的一些未指定的行为,这有点乱.在这种特殊情况下,有两个:sun.net.www.protocol.file.Handlersun.net.www.protocol.jar.Handler,它们各自处理目录大小写略有不同.基于一些实验,这是他们每个人做的事情:

sun.net.www.protocol.file.Handler:

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,但我认为没有更好的.我希望这有帮助!

  • 这太好了,谢谢。遗憾的是,即使`file.txt` 是一个普通文件,`getResource("path/to/file.txt/")` 也会返回非空值。 (2认同)