有没有办法判断类路径资源是文件还是目录? [英] Is there a way to tell if a classpath resource is a file or a directory?
问题描述
例如,假设com.google包存在于某个JAR中的某个地方(Guava,此代码段)会在 stream.read()
行中抛出NullPointerException(!)。例如)。
For example, this snippet throws a NullPointerException(!) on the stream.read()
line, assuming the com.google package exists in a JAR somewhere (Guava, for example).
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()!
如果 com / google
与在文件系统而不是JAR中的软件包,那么代码片段根本不会崩溃。实际上,它似乎读取了该目录中的文件,用换行符分隔,但我无法想象在任何地方都指定了行为。
If com/google
is swapped with a package that's in the file system rather than a JAR, then the snippet doesn't crash at all. In fact, it seems to read the files in that directory, separated by newlines, though I can't imagine that behaviour is specified anywhere.
是否有办法测试资源路径com / google指向普通资源文件或目录?
Is there a way test if the resource path "com/google" points to a "normal" resource file or to a directory?
推荐答案
这有点由于加载这些资源所涉及的协议处理程序的一些未指定的行为导致的混乱。在这种特殊情况下,有两种: sun.net.www.protocol.file.Handler
和 sun.net.www.protocol.jar。处理程序
,它们每个处理目录的情况略有不同。根据一些实验,以下是他们各自做的事情:
This is a bit of a mess due to some unspecified behaviour for the protocol handlers involved in loading these resources. In this particular situation, there are two: sun.net.www.protocol.file.Handler
and sun.net.www.protocol.jar.Handler
, and they each handle the directory case a bit differently. Based on some experiments, here's what they each do:
sun.net.www.protocol.file.Handler :
-
这个
处理程序
的作用是打开FileURLConnection
,当你遇到一个目录时,你发现它的确是什么。您可以检查它是否只是一个目录:
What this
Handler
does is open aFileURLConnection
, which does exactly what you discovered it did when confronted with a directory. You can check if it's a directory just with:
if (resource.getProtocol().equals("file")) {
return new File(resource.getPath()).isDirectory();
}
sun .net.www.protocol.jar.Handler :
- 此
处理程序$ c $另一方面,c>打开
JarURLConnection
最终走向ZipCoder
。如果你看看那段代码,你会发现一些有趣的东西:jzentry
将从本机回来null
JNI调用因为JAR zip文件实际上没有包含一个名为com / google
的文件,因此它会将包含它的流返回null。
- This
Handler
, on the other hand, opens aJarURLConnection
which eventually makes its way to aZipCoder
. If you take a look at that code, you'll notice something interesting:jzentry
will come backnull
from the native JNI call because the JAR zip file does not, in fact, contain a file calledcom/google
, and so it returns null to the stream that wraps it.
然而,有一个解决方案。虽然 ZipCoder
找不到 com / google
,但它将找到 com / google /
(这是大多数ZIP接口工作的原因,出于某种原因)。在这种情况下,将找到 jzentry
,它只会返回一个空字节。
However, there is a solution. Although the ZipCoder
won't find com/google
, it will find com/google/
(this is how most ZIP interfaces work, for some reason). In that case, the jzentry
will be found, and it'll just return a null byte.
所以,通过所有这些随机特定于实现的行为,您可以通过首先尝试使用尾随 /
(这是什么的URLClassLoader
取值期望对于目录无论如何)。如果 ClassLoader.getResource()
返回非null,那么它就是一个目录。如果没有,请尝试不使用尾部斜杠。如果它返回非null,则它是一个文件。如果它仍然返回null,那么它甚至不是现有资源。
So, cutting through all these random implementation-specific behaviours, you can probably figure out if it's a directory by first trying to access the resource with a trailing /
(which is what URLClassLoader
s expect for directories anyway). If ClassLoader.getResource()
returns non-null, then it's a directory. If it doesn't, try without the trailing slash. If it returns non-null, it's a file. If it still returns null, then it's not even an existing resource.
有点hacky,但我认为没有更好的东西。我希望这有帮助!
Kinda hacky, but I don't think there's anything better. I hope this helps!
这篇关于有没有办法判断类路径资源是文件还是目录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!