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

时间:2013-11-20 19:49:42

标签: java classpath

例如,假设com.google包存在于某个JAR(例如Guava)中,此代码段会在stream.read()行上抛出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()!

如果com/google与文件系统中的包而不是JAR交换,那么该代码段根本不会崩溃。实际上,它似乎读取了该目录中的文件,用换行符分隔,但我无法想象在任何地方都指定了行为。

如果资源路径“com / google”指向“普通”资源文件或目录,是否有方法测试?

3 个答案:

答案 0 :(得分: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,最终会makes its wayZipCoder。如果您查看该代码,您会发现一些有趣的内容:jzentry将从本机JNI调用返回null,因为JAR zip文件实际上不包含名为{的文件{1}},因此它将null返回到包装它的流。

然而,有一个解决方案。虽然com/google找不到ZipCoder,但找到com/google(这是大多数ZIP界面出于某种原因工作的方式)。在这种情况下,将找到com/google/,它将只返回一个空字节。

因此,通过所有这些随机特定于实现的行为,您可以通过首先尝试使用尾随jzentrywhich is what URLClassLoaders expect for directories anyway)来访问资源,从而确定它是否是目录。如果/返回非null,那么它就是一个目录。如果没有,请尝试不使用尾部斜杠。如果它返回非null,则它是一个文件。如果它仍然返回null,那么它甚至不是现有资源。

有点hacky,但我认为没有更好的东西。我希望这有帮助!

答案 1 :(得分:1)

没有安全通用方式来检测此问题。当您使用ClassLoader.getResource()时,ClassLoader几乎可以返回URL中的任何内容,原则上即使是ClassLoader实现自己的URL方案(和协议),也可能是您以前从未见过的。

你唯一的选择是分析getResource()返回的URL,协议应该暗示它是什么(例如“file://”)。但请注意,根据环境,它可能会返回您未计划的内容。

但是只是访问一个资源,你不会关注它来自哪里(如果你正在调试配置问题,你可能会在乎,但你的代码应该不在乎)。

通常,您不应该对返回的InputStream的功能做出假设,即不要依赖它支持标记/重置等。唯一安全的操作就是简单地读取Stream。如果在读取期间发生IOException,则表示访问资源存在问题(网络连接丢失等)。

编辑:getResource()应该IMO只返回资源(例如文件或zip文件条目),但永远不会返回目录(因为它们不是资源)。但是我不会指望每个可能的ClassLoader这样做,我不确定正确的行为是什么(如果它甚至指定在某处)。

答案 2 :(得分:-3)

我认为有两种解决方案。

  1. 基于路径本身分析的朴素解决方案。如果它以.jar.zip.war.ear结尾,则为文件。否则它是一个目录。我认为这种方法在99.99%的情况下都有效,除非有人试图让你故意失败。例如,通过定义看起来像目录但是文件的软链接,反之亦然。
  2. 尝试模拟相对于当前工作目录解释类路径路径的JVM逻辑。因此,使用new File(".")检索当前工作目录,然后使用classpath,拆分它,并为每个元素使用new File(".", classPathElement),除非使用绝对路径定义它。
  3. 祝你好运。