【问题标题】:Loading a file relative to the executing jar file加载相对于正在执行的 jar 文件的文件
【发布时间】:2011-04-07 08:18:00
【问题描述】:

问题说明了一切。

在我的情况下,特殊之处在于当前工作目录不是 jar 文件的位置,而是c:\Windows\system32(我的 jar 文件是由 windows 使用右键菜单启动的,我想将文件夹的路径传递为jar 的参数)。

现在我想加载一个名为 config.xml 的配置文件,它与 jar 位于同一文件夹中。当然,该文件的目的是为 jar 提供设置。对我来说重要的是 xml 文件位于 jar 文件的外部以便于编辑。

我很难加载该文件。 Windows 执行该行

cmd /k java -jar D:\pathToJarfile\unpacker-0.0.1-SNAPSHOT-jar-with-dependencies.jar

使用 cmd /k 调用整个过程会打开 Windows 命令提示符,以便我可以看到 jar 的输出。

我不能使用new File(".")System.getProperty("user.dir") 作为相对路径,因为这些函数分别返回C:\Windows\system32\.C:\Windows\system32(这是Windows 执行AFAIK 的所有内容的工作文件夹)。

Launcher.class.getResourceAsStream("/../config.xml") 也没有成功。由于该路径以/ 开头,因此搜索从 jar 的根节点开始。转到../config.xml 正好指向该文件,但调用返回null

有人能指出我正确的方向吗?我真的被困在这里了。这个文件加载的东西真的每次都让我很烦......

我自己的要求:

  • 我不想在 java 源代码中硬编码路径
  • 我不想将文件路径作为参数传递给java -jar 调用(既不作为main(String[] args) 的参数,也不使用-Dpath=d:\... 设置系统属性)

除了原来的问题,我在使用jar-with-dependencies时很难让maven2将Class-Path: .放入MANIFEST.MF(BalusC发布的解决方案)。 问题是该行出现在常规 jar 的 MANIFEST 文件中,而不是 jar-with-dependencies.jar 的 MANIFEST 文件中(生成了 2 个 jar 文件)。 对于任何关心我是如何做到的人:

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.2-beta-5</version>
    <configuration>
      <archive>
        <manifest>
          <mainClass>${mainClass}</mainClass>
          <addClasspath>true</addClasspath>
          <!--at first, i tried to place the Class-Path entry
              right here using <manifestEntries>. see below -->
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
    <executions>
      <execution>
        <goals>
          <goal>attached</goal>
        </goals>
        <phase>package</phase>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>${mainClass}</mainClass>
            </manifest>
            <!--this is the correct placement -->
            <manifestEntries>
              <Class-Path>.</Class-Path>
            </manifestEntries>
          </archive>
        </configuration>
      </execution>
    </executions>
  </plugin>

【问题讨论】:

    标签: java resources jar path


    【解决方案1】:

    这是使用Class.getProtectionDomain() 的一种可能解决方案:

    final Class<?> referenceClass = YourMainClass.class;
    final URL url =
        referenceClass.getProtectionDomain().getCodeSource().getLocation();
    
    try{
        final File jarPath = new File(url.toURI()).getParentFile();
        System.out.println(jarPath); // this is the path you want 
    } catch(final URISyntaxException e){
        // etc.
    }
    

    YourMainClass 可以替换为 jar 中的任何类。


    来自Class.getProtectionDomain() 文档:

    Returns the ProtectionDomain of this class.
    If there is a security manager installed, this method first calls
    the security manager's checkPermission method with a
    RuntimePermission("getProtectionDomain") permission to ensure it's
    ok to get the ProtectionDomain.
    
    Returns:
      the ProtectionDomain of this class
    Throws:
      SecurityException - if a security manager exists and its
      checkPermission method doesn't allow getting the ProtectionDomain.
    

    【讨论】:

    • 如果我需要代码中的路径,很高兴知道这一点。目前我没有,所以我会尝试使用 BalusC 的答案。
    【解决方案2】:

    要使Launcher.class.getResourceAsStream("/../config.xml") 工作,您需要将其路径添加到JAR 的MANIFEST.MF 文件的Class-Path 条目中。这是正常的做法。

    【讨论】:

    • 我需要将绝对路径放入MANIFEST.MF 还是.. 就足够了?后者将是可取的。抱歉,我没有尝试而是询问,这台机器上没有我的 IDE。
    • 不,相对于 JAR 文件本身的路径。如果您想将config.xml 与JAR 文件本身放在同一个文件夹中,那么Class-Path: . 就足够了(不要忘记在MANIFEST.MF 的末尾添加一个空行!)。然后您可以通过getResourceAsStream("config.xml") 获取config.xml。保持简单:)
    • 这是一个非常好的方法,但我无法让它发挥作用。原因是生成jar-with-dependencies 的maven 程序集插件。在常规的 .jar 文件中,我的 MANIFEST.MF 被正确放入 jar 中,但 jar-with-dependencies 文件没有使用我指定的清单:-/ 有人知道快速解决方案吗?
    • 不好意思,我不会用Maven,所以不能详细讲。您至少应该在某个地方指定要包含在类路径中的额外依赖路径。顺便说一下,对上一条评论的更正,如果Launcher 类本身在不同的包中,您应该使用"/config.xml" 作为资源名称。否则,它看起来是相对于 Launcher 类的位置(在 JAR 中)。
    • 我更新了这个问题,因为我想出了 maven2 的东西。我现在可以使用 InputStream fromFile = Launcher.class.getResourceAsStream("/config.xml"); 加载 config.xml 很好的答案,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多