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

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

所以,如果foo.jar在C:FOO ,我想要得到那个路径,不管我当前的工作目录是什么。


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

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

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


最适合我的解决方案:

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

这应该解决空间和特殊字符的问题。


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

  • 将该Class转换为URL
  • URL转换为File
  • 理解这两个步骤非常重要,而不是混淆它们。

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

    步骤1: ClassURL

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

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

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

  • 两者都有优点和缺点。

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

    getResource方法产生类的完整URL资源路径,从中你将需要执行额外的字符串操作。 它可能是一个file: path,但它也可能是jar:file:或者甚至在OSGi框架内执行时,比如bundleresource://346.fwk2106232034:4/foo/Bar.class 。 相反, getProtectionDomain方法甚至可以在OSGi内生成一个file: URL。

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

    第2步:到File URL

    无论哪种方式,一旦你有一个URL ,下一步就是转换为一个File 。 这是它自己的挑战; 请参阅Kohsuke Kawaguchi的博客文章了解详细信息,但总之,只要URL完全格式良好,您就可以使用new File(url.toURI())

    最后,我会极力劝阻使用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库中找到这些方法:

  • org.scijava.util.ClassUtils
  • org.scijava.util.FileUtils。
  • 链接地址: http://www.djcxy.com/p/56793.html

    上一篇: How to get the path of a running JAR file?

    下一篇: Get the application's path