加载相对于执行jar文件的文件

这个问题说明了一切。

我的特殊情况是当前的工作目录不是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:\...来设置系统属性)

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

  maven-assembly-plugin 2.2-beta-5    ${mainClass} true <!--at first, i tried to place the Class-Path entry right here using . see below -->    jar-with-dependencies      attached  package   jar-with-dependencies    ${mainClass}    .       

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

这是使用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.