Java 有没有办法判断类路径资源是文件还是目录?
例如,假设com.google包存在于某个JAR中(例如Guava),该代码段在Java 有没有办法判断类路径资源是文件还是目录?,java,classpath,Java,Classpath,例如,假设com.google包存在于某个JAR中(例如Guava),该代码段在stream.read()行上抛出一个NullPointerException(!) 如果将com/google与文件系统中的包交换,而不是与JAR交换,那么代码片段根本不会崩溃。事实上,它似乎在读取该目录中由新行分隔的文件,尽管我无法想象在任何地方都指定了该行为 如果资源路径“com/google”指向“普通”资源文件或目录,是否有方法测试?我认为有两种解决方案 基于路径本身分析的简单解决方案。如果它以.jar或.
stream.read()
行上抛出一个NullPointerException(!)
如果将com/google
与文件系统中的包交换,而不是与JAR交换,那么代码片段根本不会崩溃。事实上,它似乎在读取该目录中由新行分隔的文件,尽管我无法想象在任何地方都指定了该行为
如果资源路径“com/google”指向“普通”资源文件或目录,是否有方法测试?我认为有两种解决方案
.jar
或.zip
或.war
或.ear
结尾,则它是一个文件。否则它就是一个目录。我认为这种方法在99.99%的情况下有效,除非有人故意让你失败。例如,定义看起来像目录但却是文件的软链接,反之亦然新文件(“.”
)检索当前工作目录,然后获取类路径,将其拆分,并为其每个元素使用新文件(“.”,classPathElement)
,除非它是使用绝对路径定义的李>
祝你好运。没有安全通用的检测方法。当您使用ClassLoader.getResource()时,ClassLoader实际上可以返回URL中的任何内容,原则上,如果ClassLoader实现自己的URL方案(和协议),甚至可以返回您以前从未见过的内容
您唯一的选择是分析getResource()返回的URL,协议应该提示它是什么(例如,“file://”)。但请注意,根据环境的不同,它可能会返回您没有计划的东西
但要仅访问资源,您不必关心它来自何处(如果您正在调试配置问题,您可能会关心,但您的代码不应该关心)
一般来说,您不应该对返回的InputStream的功能进行假设,即不要依赖它来支持标记/重置等。唯一安全的操作就是简单地读取流。如果在读取期间发生IOException,则表示资源访问有问题(网络连接丢失等)
EDIT:getResource()应该只返回资源(例如文件或zip文件条目),而不返回目录(因为它们不是资源)。但是,我不会指望所有可能的类加载器都会这样做,而且我也不确定正确的行为是什么(如果它在某个地方被指定)。这有点混乱,因为加载这些资源时涉及的协议处理程序的一些未指定的行为。在这种特殊情况下,有两种:
sun.net.www.protocol.file.Handler
和sun.net.www.protocol.jar.Handler
,它们各自处理目录大小写的方式略有不同。根据一些实验,以下是它们各自的作用:
sun.net.www.protocol.file.Handler:
- 这个
处理程序所做的是打开一个,当遇到一个目录时会打开一个。您可以使用以下命令检查它是否为目录:
if (resource.getProtocol().equals("file")) { return new File(resource.getPath()).isDirectory(); }
- 另一方面,此
,打开一个最终指向处理程序
。如果您查看该代码,您会注意到一些有趣的事情:ZipCoder
将从本机JNI调用返回jzentry
,因为JAR zip文件实际上不包含名为null
的文件,因此它会将null返回到封装它的流com/google
ZipCoder
找不到com/google
,但它会找到com/google/
(出于某种原因,大多数ZIP接口都是这样工作的)。在这种情况下,将找到jzentry
,它只返回一个空字节
因此,通过分析所有这些随机的特定于实现的行为,您可能可以通过首先尝试使用尾部的/
()访问资源来确定它是否是一个目录。如果ClassLoader.getResource()
返回非null,则它是一个目录。如果没有,请尝试不使用尾部斜杠。如果它返回非null,则它是一个文件。如果它仍然返回null,那么它甚至不是现有资源
有点老套,但我觉得没有比这更好的了。我希望这有帮助 也许我可以把我的问题说得更清楚些。我说的不是类路径条目,而是类路径资源,即那些jar/war中的文件。例如,Maven speak中的src/main/resources。@塔维安·巴恩斯,你的问题很清楚。这就是我所说的。一旦可以读取类路径条目,就可以确定类路径资源的类型。如果条目是文件路径,只需使用常规文件API检查资源的类型。如果它是一个jar,请使用
JarInputStream
哦,好吧,我不知道你是想扫描类路径并自己打开条目。虽然这是合理的,但我希望能够使用现有的类加载器基础结构处理任意类路径。否则我的应用程序将在异域环境中崩溃。资源不是文件。试试{stream.read();System.out.println(“它在文件系统上!”;}catch(NullPointerException npe){System.out.println(“它在一个罐子里!”);}
@AdrianPetrescu我想区分类路径目录和文件,而不是“罐子里的文件”和“文件系统上的文件或目录”。此外,我不希望依赖任何未记录的内容。我想答案可能是这样的。我确实这样对待类路径资源,但如果有人意外通过com/co,我希望做一些比在以后的read()
中抛出NPE更聪明的事情
if (resource.getProtocol().equals("file")) {
return new File(resource.getPath()).isDirectory();
}