【问题标题】:How to get the path of a running JAR file?如何获取正在运行的 JAR 文件的路径?
【发布时间】:2010-09-24 03:32:52
【问题描述】:

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

所以,如果 foo.jarC:\FOO\ 中,那么无论我当前的工作目录是什么,我都想获得该路径。

【问题讨论】:

  • 查看 Fab 的答案,了解在路径包含空格时有效的解决方案。另外,请注意,下面的一些答案解决了标题中的问题(jar 路径),一些解决了问题本身(包含 jar 的文件夹的路径),还有一些提供了 jar 文件中类的路径。
  • 在 ANT 中使用时要小心! ============== 我调用 String path = SomeClass.class.getProtectionDomain().getCodeSource().getLocation().getPath();并得到:/C:/apache-ant-1.7.1/lib/ant.jar 不是很有用!
  • 有趣。我使用它的原始代码从未在 ant 中运行过,所以这对我来说不是问题。
  • @Dino Fancellu,我完全经历了你所描述的。在开发期间工作,在构建到 jar 时失败。

标签: java path jar executable-jar


【解决方案1】:
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

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

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

【讨论】:

  • toURI() 步骤对于避免特殊字符(包括空格和加号)问题至关重要。正确的一行是:return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); 使用URLDecoder 不适用于许多特殊字符。有关详细信息,请参阅下面的答案。
  • 注意:这里返回的路径包括jar文件的名称
  • 这不是指向jar文件,而不是运行目录吗?您必须对结果 getParentFile() 进行这项工作。
  • 在 Java 8 之前使用此方法;将此方法放在外部 Jar 中的类中,通过类路径加载,然后将给出外部 jar 的路径而不是实际运行的 Jar。
  • 这个答案有很多赞成票,我认为是因为日期,但现在有一天这不起作用,在调用新文件(URI)时,你会得到一个直接的异常,。 toURI 也可以为空
【解决方案2】:

对我来说最好的解决方案:

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

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

【讨论】:

  • 还有一点注意:当从 Jar 调用这个函数时,jar 的名称会附加在我的末尾,因此必须执行:path.substring(0, path.lastIndexOf("/ ") + 1);
  • / 不一定是路径分隔符。您应该改为 (new File(path)).getParentFile().getPath()。
  • 这里附加 JAR 文件名没有问题。 UTF 转换似乎是与 Linux 上的@Iviggiani one's (URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) 相结合的完美解决方案。但是,我没有在 Windows 上尝试。
  • 谢谢,这让我可以在 Linux 和 Windows 中使用 FileInputStream 将文件加载到我的 JAR 外部。只需在文件名前添加解码路径...
  • 注意:不推荐使用URLDecoder解码特殊字符。特别是像+ 这样的字符将被错误地解码为空格。详情见我的回答。
【解决方案3】:

要获取给定ClassFile,有两个步骤:

  1. Class 转换为URL
  2. URL 转换为File

了解这两个步骤很重要,而不是将它们混为一谈。

获得File 后,您可以调用getParentFile 来获取包含文件夹,如果这是您需要的话。

第 1 步:ClassURL

正如其他答案中所讨论的,有两种主要方法可以找到与 Class 相关的 URL

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

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

两者各有利弊。

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

getResource 方法会生成类的完整 URL 资源路径,您需要从中执行额外的字符串操作。它可能是file: 路径,但也可能是jar:file:,甚至在OSGi 框架中执行时也可能是bundleresource://346.fwk2106232034:4/foo/Bar.class 之类的更糟糕的东西。相反,getProtectionDomain 方法即使在 OSGi 中也能正确生成 file: URL。

请注意,当类驻留在 JAR 文件中时,getResource("")getResource(".") 在我的测试中都失败了;两个调用都返回 null。所以我推荐上面显示的 #2 调用,因为它看起来更安全。

第 2 步:URLFile

无论哪种方式,一旦您拥有URL,下一步就是转换为File。这是它自己的挑战;详情请参阅Kohsuke Kawaguchi's blog post about it,但简而言之,只要网址格式完全正确,您就可以使用new File(url.toURI())

最后,我强烈反对使用URLDecoder。 URL 的某些字符,尤其是:/,不是有效的 URL 编码字符。来自URLDecoderJavadoc:

假设编码字符串中的所有字符都是以下之一:“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 库中找到这些方法:

【讨论】:

  • +1;迄今为止最好的答案:它将使用正确的操作系统表示法返回路径。 (例如,Windows 的 \)。
  • 关于安全性,我相信我发现Java WebStart不允许这样做。
【解决方案4】:

你也可以使用:

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

【讨论】:

  • 这对我来说效果更好,因为它给出了 Jar 的路径,而不是类的路径!
  • 也为我工作。结合 Fab 的答案,它会变得更好!
  • 我同意,最好返回 .jar,而不是 .jar 调用的类。
【解决方案5】:

使用 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"));
    }
}

(本例取自a similar question。)

要查找目录,您需要手动拆分 URL。 jar URL 的格式见JarClassLoader tutorial

【讨论】:

  • 我的 JAR 文件被混淆了,所以这个答案不能解决我的问题。但我没有在问题中指定,所以这仍然是一个有效的答案。
  • 如果它被混淆了,使用 Test.class.getName() 并做适当的修改。
  • @JonSkeet 您的回答有很多问题:1. 不会有NPE 因为您没有回答所提出的问题(询问了 JAR 目录的路径并且您回答了关于完全不同的问题:上课路径)。 2.正如其他人所指出的,我遇到了同样的问题,它不适用于小程序。 3.返回的路径根本不是规范路径表示:jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class
  • @WhiteAngel: 1) 我帖子的最后一行表明您需要查看 URL 并将其分开以获取 jar 文件。我同意这不是最完整的答案,但我不认为值得争论(尤其是 10 年后......)真的那么糟糕 2)任何 cmets here中都没有提到 Applet > - 奇怪的是,我没有时间查看所有关于我碰巧发布答案的问题的所有答案。 3) 同样,我链接到 jar URL 的格式。
  • @WhiteAngel:这是我写过的最好的答案吗?没有。有你说的那么糟糕吗?不,我不这么认为。 (特别是就您提出的关于抛出 NPE 的声明而言,它没有。)我建议您添加自己的答案,而不是对此大惊小怪。这将是一种更积极的方法。
【解决方案6】:

我很惊讶最近没有人提议使用Path。引用如下:“Path 类包括各种方法,可用于获取有关路径的信息、访问路径的元素、将路径转换为其他形式或提取路径的一部分"

因此,一个不错的选择是将Path 对象获取为:

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

【讨论】:

  • 请注意,Path 从 Java 7 开始可用。
【解决方案7】:

唯一适用于 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 上,toUri() 方法将抛出异常,并且您将无法到达 else 部分,对于 linux。
  • 因匿名类而损坏
【解决方案8】:

我遇到了同样的问题,我就是这样解决的:

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

希望对你有帮助。

【讨论】:

  • 不要那样做。 URL.getPath() 返回文件名,在很多情况下都会失败,比如文件路径中有空格。
【解决方案9】:

这里是对其他 cmets 的升级,在我看来这对于具体的细节不完整

在 .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"));

【讨论】:

  • 注意:不推荐使用URLDecoder解码特殊字符。特别是像+ 这样的字符将被错误地解码为空格。详情见我的回答。
  • 不建议在文件名中使用特殊字符。
  • URLDecoder,尽管它的名字,是用于解码 URL 和表单参数名称和值,而不是 URL。
【解决方案10】:

为了获取运行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
【解决方案11】:

如果您真的在寻找一种简单的方法来获取您的 JAR 所在的文件夹,您应该使用这个实现。 像这样的解决方案很难找到,许多解决方案不再受支持,许多其他解决方案提供文件的路径而不是实际目录。这比您要找到的其他解决方案更容易,并且适用于 java 1.12 版。

new File(".").getCanonicalPath()

从其他答案中收集输入也很简单:

String localPath=new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile().getPath()+"\\"; 

两者都将返回具有这种格式的字符串:

"C:\Users\User\Desktop\Folder\"

简明扼要。

【讨论】:

    【解决方案12】:

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

    使用

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

    【讨论】:

    • 它可以是一个目录,如果你从文件系统而不是 JAR 文件加载你的类,例如调试时。
    【解决方案13】:

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

    相反,我喜欢以下解决方案无处不在:

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

    【讨论】:

    • 您是否在小程序或应用程序中尝试过。使用 Java Web Start 启动?我的理解是它在这两种情况下都会失败(即使应用程序是受信任的)。
    • 这个方案只能返回“.”的位置 JAR 文件中,而不是 JAR 文件的位置。
    • 注意:不推荐使用URLDecoder解码特殊字符。特别是像+ 这样的字符将被错误地解码为空格。详情见我的回答。
    • 在Spring boot中,会抛出NullPointerException
    • 如果 JAR 中没有资源,您将拥有 NPE
    【解决方案14】:

    在我终于找到一个可行的(和简短的)解决方案之前,我不得不搞砸了很多。
    jarLocation 可能带有 file:\jar:file\ 之类的前缀,可以使用 String#substring() 删除。

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

    【讨论】:

      【解决方案15】:

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

        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不太了解,但是处理本地文件可能无法下载应用程序。?

      【讨论】:

      • 有几种内置方法可以解码路径。无需编写自己的代码。
      【解决方案16】:
      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 上运行良好

      【讨论】:

        【解决方案17】:

        我尝试使用

        获取 jar 运行路径
        String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        

        c:\app>java -jar application.jar

        运行名为“application.jar”的 jar 应用程序,在 Windows 上的文件夹“c:\app”中,字符串变量“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”,我注意到它有效.

        【讨论】:

          【解决方案18】:

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

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

          java -jar my-jar.jar .
          

          我使用. 传递当前工作目录。

          更新

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

          【讨论】:

            【解决方案19】:
            String path = getClass().getResource("").getPath();
            

            路径总是指向 jar 文件中的资源。

            【讨论】:

            • 该路径字符串仍需要根据您的需要进行简化。 String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
            • 当类驻留在 JAR 文件中时,getResource("")getResource(".") 在我的测试中都失败了;两次调用都返回 null。
            • 这会抛出NullPointerException
            【解决方案20】:

            试试这个:

            String path = new File("").getAbsolutePath();
            

            【讨论】:

            • 如果您使用这样的绝对命令调用该 jar,则此解决方案不起作用: /home/program/java8/bin/java -jar /home/program/myjar.jar 它指出在这种情况下,到 /home/ 目录而不是 jar 目录。我测试过了
            【解决方案21】:

            这段代码帮助我识别程序是否在 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;
                }
            }
            

            如果我需要获取 JAR 文件的 Windows 完整路径,我正在使用这种方法:

                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;
                    }
                }
            }
            

            【讨论】:

              【解决方案22】:

              令人沮丧的是,当您在 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");
              }
              

              【讨论】:

                【解决方案23】:

                不太确定其他人,但在我的情况下,它不适用于“可运行的 jar”,我通过将 phchen2 答案和来自此链接的另一个代码一起修复代码来使其工作:How to get the path of a running JAR file? 代码:

                               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");
                

                【讨论】:

                  【解决方案24】:

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

                  【讨论】:

                    【解决方案25】:

                    对于jar文件路径:

                    String jarPath = File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
                        .toURI()).getPath();
                    

                    获取该jar文件的目录路径:

                    String dirPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
                                            .toURI()).getParent();
                    

                    上面两行的结果是这样的:

                    /home/user/MyPrograms/myapp/myjar.jar(用于jar路径)

                    /home/user/MyPrograms/myapp(用于目录路径)

                    【讨论】:

                      【解决方案26】:

                      提到它仅在 Windows 中进行检查,但我认为它在其他操作系统上也能完美运行 [Linux,MacOs,Solaris] :)。


                      我在同一目录中有 2 .jar 文件。我想从一个 .jar 文件中启动另一个位于同一目录中的 .jar 文件。

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


                      警告!

                      • 以下似乎在我所做的所有测试中都运行良好 文件夹名称为 ;][[;'57f2g34g87-8+9-09!2#@!$%^^&amp;()()%&amp;$%^@# 效果很好。
                      • 我正在使用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&lt;?&gt; 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;
                          }
                      

                      【讨论】:

                        【解决方案27】:

                        这段代码对我有用:

                        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;
                          }
                        

                        【讨论】:

                          【解决方案28】:

                          上述方法在我的 Spring 环境中对我不起作用,因为 Spring 将实际类隐藏到一个名为 BOOT-INF 的包中,因此不是运行文件的实际位置。我找到了另一种通过已授予运行文件的Permissions 对象检索运行文件的方法:

                          
                          public static Path getEnclosingDirectory() {
                              return Paths.get(FileUtils.class.getProtectionDomain().getPermissions()
                                      .elements().nextElement().getName()).getParent();
                          }
                          

                          【讨论】:

                            【解决方案29】:

                            此方法从存档中的代码调用,返回 .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);
                              } 
                            
                            

                            源自代码:Determine if running from JAR

                            【讨论】:

                            • "它应该可以在 Windows 或 Unix 中工作。"但在任何小程序和每个应用程序中都会失败。使用 JWS 启动。
                            【解决方案30】:

                            getProtectionDomain 方法有时可能不起作用,例如当您必须找到一些核心 java 类的 jar 时(例如,在我的情况下,IBM JDK 中的 StringBuilder 类),但是以下工作无缝:

                            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() 不会像您认为的那样做。任何特殊字符都将被百分比编码。
                            猜你喜欢
                            • 2016-10-20
                            • 2012-07-21
                            • 1970-01-01
                            • 2011-08-06
                            • 1970-01-01
                            • 2012-02-03
                            • 2018-10-14
                            相关资源
                            最近更新 更多