【问题标题】:How do I access the resources directory for a calling program in Java如何访问 Java 中调用程序的资源目录
【发布时间】:2023-03-13 05:04:01
【问题描述】:

我有一个程序使用的库。该库在资源文件夹中加载一个特殊目录。

在图书馆里我有方法

public class DataRegistry{

    public static File getSpecialDirectory(){
        String resourceName = Thread.currentThread().getContextClassLoader().getResource("data").getFile().replace("%20", " ");
        File file = new File(resourceName);
        return file;
    }

}

在我的程序中,我有 main 方法

public static void main(String args[]){
    System.out.println(Data.getSpecialDirectory());
}

当我在数据程序的 junit 测试中执行 getSpecialDirectory() 时,资源被获取并且一切正常。

当我在数据程序(导入的 jar)之外的 main 方法中执行 getSpecialDirectory() 时,我得到的是 jars 数据目录,而不是执行线程的程序所期望的目录。

我认为获取父类加载器会解决这个问题......我相信我在这里的理解可能有一个基本问题。

为了清楚起见:

(库) 该文件第 15 行:https://gist.github.com/AnthonyClink/11275442

(用法) 该文件的第 31 行: https://gist.github.com/AnthonyClink/11275661

我的 poms 可能与它有关,因此分享它们可能很重要:\

(库) https://github.com/Clinkworks/Neptical/blob/master/pom.xml

(用法) https://github.com/Clinkworks/Neptical-Maven-Plugin/blob/master/pom.xml

【问题讨论】:

  • 你想达到什么目的?获取相对于您的 DataMojo 类的文件夹的路径?

标签: java jar classloader


【解决方案1】:
  1. Maven 使用 target/classes 和 target/test-classes 目录来组成用于运行单元测试的类路径。您的 src/main/resources 和 src/test/resources 的内容与已编译的 Java 源代码(.class 文件)一起被复制到这些位置。
  2. java.lang.ClassLoader.getResource 返回 java.net.URL
  3. 在单元测试情况下,ClassLoader.getResource 返回一个 file:// 方案 URL,您的代码按预期工作。
  4. 当您的代码打包在 jar 文件中时执行时,ClassLoader.getResource 不再返回 file:// 方案 URL。不能,因为资源不再是文件系统中的单独实体 - 它被埋在 jar 文件中。你实际得到的是一个 jar:file:// 计划 URL。
  5. jar:无法通过 [j​​ava.io.File] 对象访问 URL。

如果您只需要读取资源的内容,您应该使用java.lang.ClassLoader.getResourceAsStream(...) 并从中读取内容。

请注意,无法更新类加载器资源的内容。

【讨论】:

  • 我认为他想要父文件夹,然后获取一些与该文件夹相关的其他资源 - 在名为 data 的子目录中
  • 对,这是只读的……但是我的问题是不知道如何读取流,而是如何获取文件的 url。我正在使用 maven,按照惯例,我希望库的用户使用 maven。 Maven 确实编译了这些资源,我不想将 url 指向 jar 文件,我想要用户应用程序类根目录的 url。由于该库位于 jar 中,因此我似乎无法定位正确的目录。如果您可以帮助我定位该目录,我将非常乐意接受这个详细的答案。
  • 没有文件。没有文件系统。不要传递 java.io.File 对象,而是传递从 j.l.ClassLoader.getResource(...) 获得的 URL
【解决方案2】:
  1. 您想要加载 Java 程序的目录吗?可以试试

    文件 f = new File(".").getCanconicalFile();

  2. 或者如果你想要所有的地方可以尝试从 System.env 解析类路径或使用默认的类加载器

  3. 如果您想要一个与加载类的 jar 相关的目录:引用 http://www.nakov.com/blog/2008/06/11/finding-the-directory-where-your-java-class-file-is-loaded-from/

    URL classesRootDir = getClass().getProtectionDomain().getCodeSource().getLocation();

上面返回加载你的.class时使用的基本目录 文件。它不包含包裹。它包含类路径 仅目录。例如,在上面的控制台应用程序中 返回如下内容:

file:/C:/Documents%20and%20Settings/Administrator/workspace/TestPrj/bin/

在 Web 应用程序中,它返回如下内容:

file:/C:/Tomcat/webapps/MyApp/WEB-INF/classes/

仅供参考,如果运行程序的用户 ID 无法读取所有文件夹,这可能适用:http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getProtectionDomain%28%29

  1. 或将调用类的.class对象作为参数传递并获取其类加载器

【讨论】:

  • 您永远不应该使用 java.io.File 对象来读取 jar 资源或 Web 资源的内容。这依赖于应用程序服务器在部署时爆炸您的 WAR 文件——其中许多根本不这样做。 servlet 和 JDK API 提供了其他机制来执行此操作。
  • 这是怎么做到的? “getClass().getProtectionDomain().getCodeSource().getLocation()”可能是一场战争?猜想需要检查文件对象是文件还是目录,否则取父项?
  • 不知道新的 File(".") 非常漂亮,谢谢。
【解决方案3】:

据我所知,无法保证您拥有资源目录。 Java 提供了以InputStream 形式获取资源的方法,但没有任何方法可以轻松获取资源的文件,尽管可以为给定资源获取get the URL

如果您的应用程序需要一个特殊的工作目录,我建议您将其作为系统属性、程序参数、Web 应用程序参数或其他可以让您知道应用程序文件位置的东西传递。您甚至可以使用作为资源包含在应用程序中的 ZIP 文件填充此目录,因为 Java 中的 ZIP 库确实接受输入流作为参数。

【讨论】:

    【解决方案4】:

    虽然用户@t​​gkprog 是正确的并且他的答案是正确的,但我很难想象您真的想要您似乎要求的内容以及他在 (3) 中正确回答的内容。请编辑您的问题并解释

    • 如果将resourceName 打印到控制台,输出应该是什么样子,
    • 如果您真的想要 JAR 文件的位置(在我的测试用例中,类似于 file:/C:/Users/Alexander/.m2/repository/com/clinkworks/neptical/0.0.1-SNAPSHOT /data,这没有意义,因为您不想读取甚至写入本地 Maven 缓存),
    • 或者如果您更希望直接从 JAR 文件或任何其他位置(例如当前工作目录等)读取资源。

    否则恐怕没有好办法回答这个问题。

    【讨论】:

    • 如果您从 IDE 中运行,我认为它会在本地 maven 缓存中......在已部署的应用程序中可以是任何目录,只要您已将该路径添加到类路径
    • 嗯,一个稳定的解决方案应该适用于所有环境,而不是假设特定的运行时部署场景 - 至少没有一个原始发布者甚至没有描述过。因此我询问更详细的解释。
    猜你喜欢
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多