【问题标题】:Getting the path to the directory of a given class file获取给定类文件目录的路径
【发布时间】:2009-07-27 14:15:40
【问题描述】:

我遇到了试图从类本身的 .class 文件所在的同一目录中读取一些配置文件的代码:

File[] configFiles = new File(
    this.getClass().getResource(".").getPath()).listFiles(new FilenameFilter() {
        public boolean accept(File dir, String name) {
            return name.endsWith(".xml");
        }
});

显然这在某些情况下有效(可能在 Resin 中运行代码时),但对我来说,运行 Tomcat 时,它会因 NPE 而失败,因为getClass().getResource(".") 返回null

一位同事建议创建另一个配置文件,其中包含所有“.xml”配置文件的列表(它确实可以在这里工作,因为它保持完全静态),并且你不应该真的尝试在 Java 中做这样的事情.

不过,我想知道是否有 some 好方法,它普遍适用,用于获取给定 .class 文件所在目录的路径?我想你可以像这样从 .class 文件本身的路径中获取它:

new File(this.getClass().getResource("MyClass.class").getPath()).getParent()

...但这是唯一/最干净的方式吗?

编辑:为了澄清起见,假设我们知道这是在以这样一种方式部署的应用程序中使用的,即 MyClass.class 将始终从 .class 文件中读取磁盘,资源将在同一目录中。

【问题讨论】:

  • 找到了这个相关问题:stackoverflow.com/questions/778187/… 它接受的答案基本上使用了我建议的内容 [ getResource("MyClass.class").getPath() ] ...但它没有直接回答是否是唯一或最好的方法。

标签: java file filepath


【解决方案1】:

我知道这个帖子很旧,但它是 Google 搜索中的最高结果,对我来说,这里没有令人满意的答案。这是我写的一些代码,它对我很有用。当然,需要注意的是它可能没有从磁盘加载,但它解释了这一点,并在这种情况下返回 null。这适用于查找“容器”,即类的根位置,无论是 jar 还是文件夹。这可能不直接满足您的需求。如果没有,请随意删除您确实需要的代码部分。

/**
 * Returns the container url for this class. This varies based on whether or
 * not the class files are in a zip/jar or not, so this method standardizes
 * that. The method may return null, if the class is a dynamically generated
 * class (perhaps with asm, or a proxy class)
 *
 * @param c The class to find the container for
 * @return
 */
public static String GetClassContainer(Class c) {
    if (c == null) {
        throw new NullPointerException("The Class passed to this method may not be null");
    }
    try {
        while(c.isMemberClass() || c.isAnonymousClass()){
            c = c.getEnclosingClass(); //Get the actual enclosing file
        }
        if (c.getProtectionDomain().getCodeSource() == null) {
            //This is a proxy or other dynamically generated class, and has no physical container,
            //so just return null.
            return null;
        }
        String packageRoot;
        try {
            //This is the full path to THIS file, but we need to get the package root.
            String thisClass = c.getResource(c.getSimpleName() + ".class").toString();
            packageRoot = StringUtils.replaceLast(thisClass, Pattern.quote(c.getName().replaceAll("\\.", "/") + ".class"), "");
            if(packageRoot.endsWith("!/")){
                packageRoot = StringUtils.replaceLast(packageRoot, "!/", "");
            }
        } catch (Exception e) {
            //Hmm, ok, try this then
            packageRoot = c.getProtectionDomain().getCodeSource().getLocation().toString();
        }
        packageRoot = URLDecoder.decode(packageRoot, "UTF-8");
        return packageRoot;
    } catch (Exception e) {
        throw new RuntimeException("While interrogating " + c.getName() + ", an unexpected exception was thrown.", e);
    }
}

【讨论】:

    【解决方案2】:

    是什么让你认为在磁盘上它自己的目录中有一个类文件?

    一个类可以是:

    • 完全在内存中创建
    • 从网络连接加载
    • 从 jar 文件加载

    您可以获得用于创建类本身的 URL,如果它以 file:// 开头,那么您可以获得其余的……但它不适用于所有类。

    【讨论】:

    • 是的,我认为这几乎就是我的同事在提出替代方案时的意思...但是有 种场景,当您确实知道该类将始终从磁盘上的文件-因此,如果是这种情况,我在问题中建议的方法是最干净的吗?感谢您提供有关检查 URL 开头的提示!
    • 是的,如果您添加对文件协议的检查,那么您所获得的内容对我来说是最干净的方式。
    【解决方案3】:

    如果资源与 .class 文件位于同一文件夹中,则它应该可以通过类路径访问,并且可以直接通过 getResourceAsStream 加载。

    this.getClass().getResourceAsStream( "filename.xml" )
    

    如前所述,类本身可以远程加载,也可以在没有正确“路径”的地方加载(例如,从 jarfile 加载)

    【讨论】:

    • 是的,当然;我一直在寻找获取 directory 路径的最简单方法(因为我们正在从那里读取多个资源文件)
    • 啊,你想阅读所有内容吗?此时类路径中的“.xml”文件,而不必事先知道它们的名称?
    • 是的,这就是重点。 (虽然在这种情况下我们基本上知道名称,但我只想动态读取文件,以避免在某处或类似的地方列出它们。)
    【解决方案4】:

    我同意您的同事的观点,即 Java 类加载并非旨在处理此用例。 Sun Facelets 使用类似的策略,假设 URL 可以映射到文件,但它并不漂亮。我同意 Jon 的评论,即根据您的部署假设,您的 getResource 解决方案可能是最干净的。既然你问这是否是唯一的方法,我也会提供 getClass().getProtectionDomain().getCodeSource().getLocation(),它应该是类加载器实际加载你的类的 URL(你需要附加您的类包的子目录)。该策略也具有相同的 URL-to-File 假设,因此在这方面也没有更好的选择。我想不出其他通用解决方案。

    注意 getResource 返回一个编码的 URL,这意味着你不应该直接使用 getPath()。特别是,空间会导致问题,但如果您可以控制环境,这可能不是问题。考虑使用 new File(URL.toURI())。

    【讨论】:

      【解决方案5】:

      我想,您可能对 Spring 框架中的 PathMatchingResourcePatternResolver 感兴趣。您可以直接在代码中使用它来导航配置文件,也可以查找实现here

      【讨论】:

        猜你喜欢
        • 2018-05-31
        • 2013-08-28
        • 1970-01-01
        • 2010-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-21
        • 2015-12-07
        相关资源
        最近更新 更多