如何获取正在运行的JAR文件的路径?


580

我的代码在JAR文件foo.jar中运行,我需要在代码中知道正在运行的foo.jar在哪个文件夹中。

因此,如果foo.jar在中C:\FOO\,无论我当前的工作目录是什么,我都希望获取该路径。


有关路径包含空格时有效的解决方案,请参见Fab的答案。另外,请注意,下面的一些答案解决了标题中的问题(jar路径),一些解决了问题本身(包含jar的文件夹的路径),还有一些提供了jar文件中类的路径。
安迪·托马斯

32
在ANT中使用时要当心!===============我称字符串路径为SomeClass.class.getProtectionDomain()。getCodeSource()。getLocation()。getPath(); 并得到:/C:/apache-ant-1.7.1/lib/ant.jar不太有用!
Dino Fancellu 2012年

有趣。我在其中使用过的原始代码从未在ant中运行过,所以这对我来说不是问题。
Thiago Chaves 2012年

2
@Dino Fancellu,我完全体验了您的描述。在开发期间有效,构建为jar时失败。
好友2015年

Answers:


538
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

用您的班级名称替换“ MyClass”。

显然,如果您的类是从非文件位置加载的,这会做奇怪的事情。


42
toURI()步骤对于避免特殊字符(包括空格和加号)出现问题至关重要。正确的单行代码是:return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); 使用URLDecoder不适用于许多特殊字符。请参阅下面的我的答案以获取更多详细信息。
2012年

4
注意:这将返回包含jar文件名称的路径
Buddy 2015年

8
这不是指向jar文件,而不是指向运行目录吗?您将必须对结果getParentFile()进行此项工作。
FOO 2016年

1
此外,getProtectionDomain如果您要从stracktrace获取课程,则为null:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker '18

1
最多在Java 8上使用此方法;将此方法放在通过类路径加载的外部Jar中的类中,则将给出外部jar的路径,而不是实际运行的Jar。
Mr00Anderson

189

最适合我的解决方案:

String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");

这应该可以解决空格和特殊字符的问题。


8
还有一点要注意:从Jar调用此函数时,jar的名称会在我的末尾附加,因此必须执行:path.substring(0,path.lastIndexOf(“ /”)+ 1);
will824 2011年

11
/不一定是路径分隔符。您应该改为(new File(path))。getParentFile()。getPath()。
pjz 2012年

10
在此附加JAR文件名没有问题。URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");在Linux上,与@Iviggiani一个()结合使用时,UTF转换似乎是一个完美的解决方案。但是,我没有在Windows上尝试过。
ubuntudroid

2
谢谢,这使我可以在Linux和Windows中使用FileInputStream加载JAR外部的文件。只需在文件名前面添加解码路径...
giorgio79

11
当心:不建议URLDecoder用于解码特殊字符。特别是,像这样的字符+将被错误地解码为空格。有关详细信息,请参见我的答案。
2012年

153

要获得File给定的Class,有两个步骤:

  1. 将转换ClassURL
  2. 将转换URLFile

重要的是要理解两个步骤,而不要将它们混为一谈。

一旦有了File,就可以调用getParentFile来获取包含的文件夹,如果需要的话。

第1步:ClassURL

正如在其他答案中讨论的那样,有两种主要方法可以找到与URL关联的内容Class

  1. URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();

  2. URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");

两者都有优点和缺点。

getProtectionDomain方法产生类的基本位置(例如,包含JAR文件的位置)。但是,SecurityException调用时可能会抛出Java运行时的安全策略getProtectionDomain(),因此,如果您的应用程序需要在各种环境中运行,则最好在所有环境中进行测试。

getResource方法将产生该类的完整URL资源路径,您将需要从该路径执行其他字符串操作。它可能是一条file:路径,但也可能是jar:file:,甚至bundleresource://346.fwk2106232034:4/foo/Bar.class在OSGi框架中执行时更令人讨厌。相反,该getProtectionDomain方法file:甚至可以从OSGi内部正确生成URL。

注意,当类驻留在JAR文件中时,getResource("")和都getResource(".")在我的测试中失败;两次调用均返回null。因此,我建议改用上面显示的#2调用,因为它看起来更安全。

第2步:URLFile

无论哪种方式,一旦有了a URL,下一步都将转换为a File。这是它自己的挑战。有关详细信息,请参阅川口浩介的博客文章,但总之,new File(url.toURI())只要URL格式正确,就可以使用。

最后,我强烈建议您不要使用URLDecoder。该URL的一些人物:/特别,不是有效的URL编码字符。从URLDecoder Javadoc:

假定编码字符串中的所有字符均为以下之一:“ a”至“ z”,“ A”至“ Z”,“ 0”至“ 9”以及“-”,“ _”,“ 。”和“ *”。允许使用字符“%”,但将其解释为特殊转义序列的开始。

...

该解码器可以通过两种可能的方式处理非法字符串。它可以不留非法字符,也可以引发IllegalArgumentException。解码器采用哪种方法留待实施。

在实践中,URLDecoder通常不会IllegalArgumentException像上述那样抛出威胁。并且,如果您的文件路径中的空格编码为%20,则该方法似乎可以使用。但是,如果您的文件路径包含其他非字母数字字符,例如,+您将无法处理URLDecoder文件路径。

工作代码

要实现这些步骤,您可能具有类似以下的方法:

/**
 * Gets the base location of the given class.
 * <p>
 * If the class is directly on the file system (e.g.,
 * "/path/to/my/package/MyClass.class") then it will return the base directory
 * (e.g., "file:/path/to").
 * </p>
 * <p>
 * If the class is within a JAR file (e.g.,
 * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
 * path to the JAR (e.g., "file:/path/to/my-jar.jar").
 * </p>
 *
 * @param c The class whose location is desired.
 * @see FileUtils#urlToFile(URL) to convert the result to a {@link File}.
 */
public static URL getLocation(final Class<?> c) {
    if (c == null) return null; // could not load the class

    // try the easy way first
    try {
        final URL codeSourceLocation =
            c.getProtectionDomain().getCodeSource().getLocation();
        if (codeSourceLocation != null) return codeSourceLocation;
    }
    catch (final SecurityException e) {
        // NB: Cannot access protection domain.
    }
    catch (final NullPointerException e) {
        // NB: Protection domain or code source is null.
    }

    // NB: The easy way failed, so we try the hard way. We ask for the class
    // itself as a resource, then strip the class's path from the URL string,
    // leaving the base path.

    // get the class's raw resource path
    final URL classResource = c.getResource(c.getSimpleName() + ".class");
    if (classResource == null) return null; // cannot find class resource

    final String url = classResource.toString();
    final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
    if (!url.endsWith(suffix)) return null; // weird URL

    // strip the class's path from the URL string
    final String base = url.substring(0, url.length() - suffix.length());

    String path = base;

    // remove the "jar:" prefix and "!/" suffix, if present
    if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);

    try {
        return new URL(path);
    }
    catch (final MalformedURLException e) {
        e.printStackTrace();
        return null;
    }
} 

/**
 * Converts the given {@link URL} to its corresponding {@link File}.
 * <p>
 * This method is similar to calling {@code new File(url.toURI())} except that
 * it also handles "jar:file:" URLs, returning the path to the JAR file.
 * </p>
 * 
 * @param url The URL to convert.
 * @return A file path suitable for use with e.g. {@link FileInputStream}
 * @throws IllegalArgumentException if the URL does not correspond to a file.
 */
public static File urlToFile(final URL url) {
    return url == null ? null : urlToFile(url.toString());
}

/**
 * Converts the given URL string to its corresponding {@link File}.
 * 
 * @param url The URL to convert.
 * @return A file path suitable for use with e.g. {@link FileInputStream}
 * @throws IllegalArgumentException if the URL does not correspond to a file.
 */
public static File urlToFile(final String url) {
    String path = url;
    if (path.startsWith("jar:")) {
        // remove "jar:" prefix and "!/" suffix
        final int index = path.indexOf("!/");
        path = path.substring(4, index);
    }
    try {
        if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
            path = "file:/" + path.substring(5);
        }
        return new File(new URL(path).toURI());
    }
    catch (final MalformedURLException e) {
        // NB: URL is not completely well-formed.
    }
    catch (final URISyntaxException e) {
        // NB: URL is not completely well-formed.
    }
    if (path.startsWith("file:")) {
        // pass through the URL as-is, minus "file:" prefix
        path = path.substring(5);
        return new File(path);
    }
    throw new IllegalArgumentException("Invalid URL: " + url);
}

您可以在SciJava Common库中找到以下方法:


5
+1; 迄今为止最好的答案:它将使用正确的操作系统符号返回路径。(例如,对于Windows,为\)。
Bathsheba 2013年

关于安全性,我相信我发现Java WebStart不允许这样做。
托尔比约恩Ravn的安徒生

55

您还可以使用:

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();

3
这对我来说效果更好,因为它给出了Jar的路径,而不是类的路径!
T30 2014年

也为我工作。结合Fab的答案,它会变得更好!
Danielson AlvesJúnior

25

使用ClassLoader.getResource()查找当前类的URL。

例如:

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

(此示例来自类似的问题。)

要找到目录,您需要手动分解URL。有关jar URL的格式,请参见JarClassLoader教程


我的JAR文件被混淆了,所以这个答案不能解决我的问题。但是我没有在问题中指定,所以这仍然是一个有效的答案。
Thiago Chaves,2009年

12
如果混淆,请使用Test.class.getName()并进行适当的调整。
乔恩·斯基特

1
@JonSkeet您的回答有很多问题:1.不会有,NPE因为您没有回答所提出的问题(询问了JAR dir的路径,而您回答了绝对不同的问题:上课的路径)。2.正如其他人所指出的,我遇到了同样的问题,它不适用于applet。3.返回的路径根本不具有规范的路径表示形式:jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class
WhiteAngel

1
@WhiteAngel:1)我的帖子的最后一行指示您需要查看URL并将其分开以获取jar文件。我同意这不是最完整的答案,但我认为值得争论的事实(尤其是10年后……)真的不是很糟糕2)这里没有任何评论提及小程序-奇怪的是,我不我没有时间去看我刚发布答案的问题的所有答案的所有评论。3)同样,我链接到jar URL的格式。
乔恩·斯基特

2
@WhiteAngel:这是我写过的最好的答案吗?不。是否像您要证明的那样糟糕?不,我不这么认为。(特别是关于您提出的抛出NPE的主张,但事实并非如此。)我建议您添加自己的答案,而不是为此大惊小怪。那将是一个更积极的方法。
乔恩·斯基特

19

令我惊讶的是,最近没有人提议使用它Path。这里如下引文:“ Path类包括可以用来获得关于所述路径信息的各种方法,该路径的接入元件,所述路径转换为其它形式,或一路径的提取部

因此,一个很好的选择是使Pathobjest为:

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());

3
作为一个说明,Path是在Java 7中得到的起始
克里斯Forrence

15

在Linux,Mac和Windows上唯一适用于我的解决方案:

public static String getJarContainingFolder(Class aclass) throws Exception {
  CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();

  File jarFile;

  if (codeSource.getLocation() != null) {
    jarFile = new File(codeSource.getLocation().toURI());
  }
  else {
    String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
    String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
    jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
    jarFile = new File(jarFilePath);
  }
  return jarFile.getParentFile().getAbsolutePath();
}

这是行不通的。如果在Linux上,对于Linux,toUri()方法将引发异常,并且您将无法到达else部分。
Wilhelm Sorban '18年

9

我遇到了同样的问题,并以这种方式解决了这个问题:

File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());   
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");

希望对您有帮助。


不要那样做 URL.getPath()返回文件名,并且在很多情况下都会失败,例如其中带有空格的文件路径。
VGR

9

这是对其他评论的升级,在我看来,这些评论的内容不完整

在.jar文件外部(在jar的相同位置)使用相对的“文件夹”:

String path = 
  YourMainClassName.class.getProtectionDomain().
  getCodeSource().getLocation().getPath();

path = 
  URLDecoder.decode(
    path, 
    "UTF-8");

BufferedImage img = 
  ImageIO.read(
    new File((
        new File(path).getParentFile().getPath()) +  
        File.separator + 
        "folder" + 
        File.separator + 
        "yourfile.jpg"));

4
当心:不建议URLDecoder用于解码特殊字符。特别是,像这样的字符+将被错误地解码为空格。有关详细信息,请参见我的答案。
2012年

不建议在文件名中使用特殊字符。
Zon

URLDecoder,尽管名称如此,但它用于解码URL和表单参数的名称和值,而不是URL。
罗恩侯爵,

6

为了获得运行jar文件的路径,我研究了上述解决方案,并尝试了存在彼此差异的所有方法。如果这些代码在Eclipse IDE中运行,则它们所有人都应该能够找到包含指示类的文件的路径,并使用找到的路径打开或创建指示文件。

但这很棘手,当直接或通过命令行运行可运行的jar文件时,它将失败,因为从上述方法获得的jar文件的路径将在jar文件中提供内部路径,即它始终提供路径如

rsrc:project-name(也许我应该说这是主类文件的包名-指示的类)

我无法将rsrc:...路径转换为外部路径,也就是说,在Eclipse IDE外部运行jar文件时,无法获取jar文件的路径。

获取在Eclipse IDE外部运行jar文件的路径的唯一可能方法是

System.getProperty("java.class.path")

该代码行可能返回正在运行的jar文件的活动路径(包括文件名)(请注意,返回路径不是工作目录),因为java文档和某些人说它将返回所有类文件的路径。在同一目录中,但是正如我的测试是否在同一目录中包含许多jar文件一样,它仅返回正在运行的jar的路径(关于多路径问题的确确实发生在Eclipse中)。


java.class.path可以是多值的。其中这些值肯定会提供的目录或在当前类位于JAR文件,但哪一个?
罗恩侯爵,

我确认,我尝试了其他解决方案,但从未获取jar文件名。这很简单!谢谢-+1
guillaume girod-vitouchkina

5

其他答案似乎指向代码源,它是Jar文件位置,而不是目录。

采用

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();

如果要从文件系统而不是JAR文件加载类,则可以是目录,例如在调试时。
罗恩侯爵,

4

如果您是通过Gnome桌面环境(而不是从任何脚本或终端)单击jar来运行jar的,则上面选择的答案不起作用。

相反,我喜欢以下解决方案在任何地方都有效:

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }

2
您在applet或应用程序中尝试过吗?使用Java Web Start启动?我的理解是,这两种情况都将失败(即使该应用程序是受信任的)。
Andrew Thompson

此解决方案只能返回“。”的位置。的JAR文件,而不是位置 JAR文件。
罗恩侯爵

当心:不建议URLDecoder用于解码特殊字符。特别是,像这样的字符+将被错误地解码为空格。有关详细信息,请参见我的答案。
2012年

在春季靴子中,它将抛出NullPointerException
Ravi Parekh

NPE如果JAR中没有资源,您将拥有。
WhiteAngel

3

实际上,这是一个更好的版本-如果文件夹名称中有空格,则旧版本会失败。

  private String getJarFolder() {
    // get name and path
    String name = getClass().getName().replace('.', '/');
    name = getClass().getResource("/" + name + ".class").toString();
    // remove junk
    name = name.substring(0, name.indexOf(".jar"));
    name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
    // remove escape characters
    String s = "";
    for (int k=0; k<name.length(); k++) {
      s += name.charAt(k);
      if (name.charAt(k) == ' ') k += 2;
    }
    // replace '/' with system separator char
    return s.replace('/', File.separatorChar);
  }

至于失败的小程序,您通常通常都无法访问本地文件。我对JWS不太了解,但是要处理本地文件,可能无法下载该应用程序。


有几种内置的方法可以解码路径。无需编写您自己的代码。
罗恩侯爵,

3

我试图使用以下命令获取jar运行路径

String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();

c:\ app> java -jar application.jar

在Windows上的文件夹“ c:\ app ”中运行名为“ application.jar”的jar应用程序,字符串变量“ folder”的值为“ \ c:\ app \ application.jar ”,并且我在测试路径的正确性

File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }

因此,我尝试将“测试”定义为:

String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);

以正确的格式(例如“ c:\ app ”而不是“ \ c:\ app \ application.jar ”)获取路径,我注意到它可以正常工作。


3

最简单的解决方案是在运行jar时将路径作为参数传递。

您可以使用Shell脚本(Windows中的.bat,其他任何位置的.sh)自动执行此操作:

java -jar my-jar.jar .

我曾经.传递当前的工作目录。

更新

您可能希望将jar文件粘贴在子目录中,以免用户意外单击它。您的代码还应检查以确保提供了命令行参数,如果缺少参数,则应提供良好的错误消息。


3

在最终找到一个可行的(简短的)解决方案之前,我不得不四处乱逛。
可能jarLocation带有诸如file:\或的前缀jar:file\,可以使用删除String#substring()

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();

2
String path = getClass().getResource("").getPath();

该路径始终引用jar文件中的资源。


1
该路径字符串仍需要根据您的需要进行简化。String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ

4
双方getResource("")getResource(".")在我的测试中失败了,上课的时候一个JAR文件中居住; 两次调用均返回null。
2012年

2
这抛出NullPointerException
罗恩侯爵,

2
public static String dir() throws URISyntaxException
{
    URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
    String name= Main.class.getPackage().getName()+".jar";
    String path2 = path.getRawPath();
    path2=path2.substring(1);

    if (path2.contains(".jar"))
    {
        path2=path2.replace(name, "");
    }
    return path2;}

在Windows上运作良好


1

令人沮丧的是,当您在Eclipse中进行开发时,MyClass.class.getProtectionDomain().getCodeSource().getLocation()返回的/bin目录很棒,但是当您将其编译为jar时,路径中包含/myjarname.jar为您提供非法文件名的部分。

为了使代码既可以在ide中工作,又可以在将其编译到jar中后使用,请使用以下代码:

URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
    myFile = new File(applicationRootPath, "filename");
}
else{
    myFile = new File(applicationRootPath.getParentFile(), "filename");
}

1

不确定其他的,但是在我的情况下,它不能与“ Runnable jar”一起使用,我通过从phchen2答案和此链接的另一个代码一起修复代码来使其工作:如何获取正在运行的JAR文件的路径? 编码:

               String path=new java.io.File(Server.class.getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .getPath())
          .getAbsolutePath();
       path=path.substring(0, path.lastIndexOf("."));
       path=path+System.getProperty("java.class.path");

1

已经尝试了几种解决方案,但是对于(可能是特殊的)情况(在Eclipse中使用“打包外部库”导出了可运行的jar),没有一个产生正确的结果。由于某种原因,在这种情况下,所有基于ProtectionDomain的解决方案都将导致null。

通过结合上面的一些解决方案,我设法实现了以下工作代码:

String surroundingJar = null;

// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();

// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];

// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
    System.out.println("RUNNING FROM IDE!");
    // The path to the jar is the "bin" directory in that case because there is no actual .jar file.
    surroundingJar = jarDir;
}
else
{
    // Combining the path and the name of the .jar file to achieve the final result
    surroundingJar = jarDir + jarFileFromSys.substring(1);
}

System.out.println("JAR File: " + surroundingJar);


0

从归档文件中的代码调用此方法,该方法返回.jar文件所在的文件夹。它应该可以在Windows或Unix下运行。


  private String getJarFolder() {
    String name = this.getClass().getName().replace('.', '/');
    String s = this.getClass().getResource("/" + name + ".class").toString();
    s = s.replace('/', File.separatorChar);
    s = s.substring(0, s.indexOf(".jar")+4);
    s = s.substring(s.lastIndexOf(':')-1);
    return s.substring(0, s.lastIndexOf(File.separatorChar)+1);
  } 

从以下代码派生:确定是否从JAR运行


3
“它应该可以在Windows或Unix上运行。” 但会在任何applet和每个应用程序中失败。使用JWS启动。
Andrew Thompson

0

提及它仅被签入,Windows但我认为它在其他操作系统[ Linux,MacOs,Solaris] :) 上可以完美地工作。


我在同一目录中有2个 .jar文件。我希望从一个.jar文件开始.jar在同一目录中的另一个文件。

问题是,当您从cmd当前目录启动它时,该目录是system32


警告!

  • 即使在文件夹名称;][[;'57f2g34g87-8+9-09!2#@!$%^^&()()%&$%^@# 它工作得很好。
  • 我正在ProcessBuilder将以下内容与结合使用:

🍂..

//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath=  new File(path + "application.jar").getAbsolutePath();


System.out.println("Directory Path is : "+applicationPath);

//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2#@!$%^^&()` 
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();

//...code

🍂 getBasePathForClass(Class<?> classs)

    /**
     * Returns the absolute path of the current directory in which the given
     * class
     * file is.
     * 
     * @param classs
     * @return The absolute path of the current directory in which the class
     *         file is.
     * @author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
     */
    public static final String getBasePathForClass(Class<?> classs) {

        // Local variables
        File file;
        String basePath = "";
        boolean failed = false;

        // Let's give a first try
        try {
            file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());

            if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
                basePath = file.getParent();
            } else {
                basePath = file.getPath();
            }
        } catch (URISyntaxException ex) {
            failed = true;
            Logger.getLogger(classs.getName()).log(Level.WARNING,
                    "Cannot firgue out base path for class with way (1): ", ex);
        }

        // The above failed?
        if (failed) {
            try {
                file = new File(classs.getClassLoader().getResource("").toURI().getPath());
                basePath = file.getAbsolutePath();

                // the below is for testing purposes...
                // starts with File.separator?
                // String l = local.replaceFirst("[" + File.separator +
                // "/\\\\]", "")
            } catch (URISyntaxException ex) {
                Logger.getLogger(classs.getName()).log(Level.WARNING,
                        "Cannot firgue out base path for class with way (2): ", ex);
            }
        }

        // fix to run inside eclipse
        if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
                || basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
            basePath = basePath.substring(0, basePath.length() - 4);
        }
        // fix to run inside netbeans
        if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
            basePath = basePath.substring(0, basePath.length() - 14);
        }
        // end fix
        if (!basePath.endsWith(File.separator)) {
            basePath = basePath + File.separator;
        }
        return basePath;
    }

0

这段代码对我有用:

private static String getJarPath() throws IOException, URISyntaxException {
    File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
    String jarPath = f.getCanonicalPath().toString();
    String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
    return jarDir;
  }

0

这段代码对我有用,可以确定程序是否在JAR文件或IDE中执行:

private static boolean isRunningOverJar() {
    try {
        String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

        if (pathJar.toLowerCase().contains(".jar")) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}

如果需要获取Windows JAR文件的完整路径,请使用以下方法:

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("Error getting JAR path.", e);
            return null;
        }
    }

我的完整代码与使用CommandLineRunner实现的Spring Boot应用程序一起使用,以确保始终在控制台视图内执行该应用程序(错误地双击JAR文件名),我正在使用下一个代码:

@SpringBootApplication
public class Application implements CommandLineRunner {
    public static void main(String[] args) throws IOException {
        Console console = System.console();

        if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
            Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
                    "java -jar \"" + getPathJar() + "\""});
        } else {
            SpringApplication.run(Application.class, args);
        }
    }

    @Override
    public void run(String... args) {
        /*
        Additional code here...
        */
    }

    private static boolean isRunningOverJar() {
        try {
            String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

            if (pathJar.toLowerCase().contains(".jar")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }
}

-1

我用Java 7编写,在Windows 7中使用Oracle的运行时进行测试,在Ubuntu中使用开源的运行时进行测试。这对于这些系统非常适用:

任何正在运行的jar文件的父目录的路径(假设调用此代码的类是jar存档本身的直接子级):

try {
    fooDir = new File(this.getClass().getClassLoader().getResource("").toURI());
} catch (URISyntaxException e) {
    //may be sloppy, but don't really need anything here
}
fooDirPath = fooDir.toString(); // converts abstract (absolute) path to a String

因此,foo.jar的路径为:

fooPath = fooDirPath + File.separator + "foo.jar";

再次说明,未在任何Mac或更旧的Windows上对此进行过测试


-1

getProtectionDomain例如,当您必须为某些核心java类(例如,StringBuilder在IBM JDK 中的我的案例类中)找到jar时,该方法有时可能无法工作,但是以下操作是无缝的:

public static void main(String[] args) {
    System.out.println(findSource(MyClass.class));
    // OR
    System.out.println(findSource(String.class));
}

public static String findSource(Class<?> clazz) {
    String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
    java.net.URL location = clazz.getResource(resourceToSearch);
    String sourcePath = location.getPath();
    // Optional, Remove junk
    return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}

URL.getPath()并没有您认为的那样。任何特殊字符都将进行百分比编码。
VGR

-1

我还有另一种获取类的String位置的方法。

URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();

输出字符串的形式为

C:\Users\Administrator\new Workspace\...

空格和其他字符以没有的形式处理file:/。这样会更容易使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.