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

Java 有没有办法判断类路径资源是文件还是目录?,java,classpath,Java,Classpath,例如,假设com.google包存在于某个JAR中(例如Guava),该代码段在stream.read()行上抛出一个NullPointerException(!) 如果将com/google与文件系统中的包交换,而不是与JAR交换,那么代码片段根本不会崩溃。事实上,它似乎在读取该目录中由新行分隔的文件,尽管我无法想象在任何地方都指定了该行为 如果资源路径“com/google”指向“普通”资源文件或目录,是否有方法测试?我认为有两种解决方案 基于路径本身分析的简单解决方案。如果它以.jar或.

例如,假设com.google包存在于某个JAR中(例如Guava),该代码段在
stream.read()
行上抛出一个NullPointerException(!)

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


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

我认为有两种解决方案

  • 基于路径本身分析的简单解决方案。如果它以
    .jar
    .zip
    .war
    .ear
    结尾,则它是一个文件。否则它就是一个目录。我认为这种方法在99.99%的情况下有效,除非有人故意让你失败。例如,定义看起来像目录但却是文件的软链接,反之亦然
  • 尝试模拟解释相对于当前工作目录的类路径路径路径的JVM逻辑。因此,使用
    新文件(“.”
    )检索当前工作目录,然后获取类路径,将其拆分,并为其每个元素使用
    新文件(“.”,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();
      }
      
    sun.net.www.protocol.jar.Handler

    • 另一方面,此
      处理程序
      ,打开一个最终指向
      ZipCoder
      。如果您查看该代码,您会注意到一些有趣的事情:
      jzentry
      将从本机JNI调用返回
      null
      ,因为JAR zip文件实际上不包含名为
      com/google
      的文件,因此它会将null返回到封装它的流
    然而,有一个解决办法。虽然
    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();
    }