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

时间:2008-11-26 12:30:38

标签: java path jar executable-jar

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

所以,如果foo.jar在C:\FOO\中,无论我目前的工作目录是什么,我都希望得到这条路径。

32 个答案:

答案 0 :(得分:496)

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

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

显然,如果您的类是从非文件位置加载的,那么这会很奇怪。

答案 1 :(得分:186)

最适合我的解决方案:

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

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

答案 2 :(得分:143)

要获得给定File的{​​{1}},有两个步骤:

  1. Class转换为Class
  2. URL转换为URL
  3. 理解这两个步骤非常重要,而不是将它们混为一谈。

    获得File后,如果您需要,可以致电File获取包含文件夹。

    第1步:getParentFileClass

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

    1. Class

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

    3. 两者都有利有弊。

      URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");方法产生类的基本位置(例如,包含JAR文件)。但是,Java运行时的安全策略可能在调用getProtectionDomain时抛出SecurityException,因此如果您的应用程序需要在各种环境中运行,最好在所有环境中进行测试。 / p>

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

      请注意,当类位于JAR文件中时,我的测试中file:getResource("")都失败了;两个调用都返回null。所以我推荐上面显示的#2调用,因为它似乎更安全。

      第2步:getResource(".")URL

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

      最后,我会高度劝阻使用new File(url.toURI())。网址的某些字符,尤其是URLDecoder:,不是有效的网址编码字符。来自URLDecoder Javadoc:

        

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

           

      ...

           

      这种解码器可以通过两种方式处理非法字符串。它可能会单独留下非法字符,也可能会抛出IllegalArgumentException。解码器采用哪种方法留待实施。

      在实践中,/通常不会将URLDecoder投掷为上述威胁。如果您的文件路径的空格编码为IllegalArgumentException,则此方法似乎可行。但是,如果您的文件路径包含其他非字母数字字符,例如%20,则+会损坏您的文件路径。

      工作代码

      要实现这些步骤,您可能会使用以下方法:

      URLDecoder

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

答案 3 :(得分:49)

您也可以使用:

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

答案 4 :(得分:24)

使用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

答案 5 :(得分:17)

我很惊讶地发现最近没有人建议使用Path。下面是一个引用:“ Path类包括各种方法,可用于获取有关路径的信息,访问路径元素,将路径转换为其他形式,或提取路径的一部分< / EM>“

因此,一个好的选择是将Path客观化为:

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

答案 6 :(得分:14)

唯一适用于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();
}

答案 7 :(得分:8)

这是对其他评论的升级,对于

的具体细节我似乎不完整
  

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

答案 8 :(得分:8)

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

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

我希望我对你有所帮助。

答案 9 :(得分:6)

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

但是这很棘手,当直接或通过命令行运行runnable jar文件时,它将失败,因为从上面的方法获取的jar文件的路径将在jar文件中给出内部路径,即它总是给出了一条路径

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

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

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

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

这段代码行可能会返回正在运行的jar文件的生存路径(包括文件名)(注意返回路径不是工作目录),因为java文件和一些人说它会返回路径同一目录中的所有类文件,但作为我的测试,如果在同一目录中包含许多jar文件,它只返回运行jar的路径(关于多路径问题确实发生在Eclipse中)。

答案 10 :(得分:4)

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

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

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

答案 11 :(得分: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);
  }

至于使用applet失败,您通常无法访问本地文件。我对JWS了解不多,但是处理本地文件可能无法下载应用程序。?

答案 12 :(得分:3)

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

使用

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

答案 13 :(得分:3)

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

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

java -jar my-jar.jar .

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

<强>更新

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

答案 14 :(得分:3)

在我最终找到一个有效(和简短)的解决方案之前,我不得不捣乱。
jarLocation可能会带有file:\jar:file\这样的前缀,可以使用String#substring()删除。

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

答案 15 :(得分:2)

我尝试使用

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

c:\ app&gt; java -jar application.jar

在Windows上的“ c:\ app ”文件夹中运行名为“application.jar”的jar应用程序,String变量“folder”的值为“ \ c: \ app \ application.jar “我在测试路径正确性方面遇到了问题

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

所以我试着将“test”定义为:

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

以正确的格式获取路径,例如“ c:\ app ”而不是“ \ c:\ app \ application.jar ”,我发现它有效

答案 16 :(得分:2)

如果您确实在寻找一种简单的方法来获取JAR所在的文件夹,则应实施此格式的解决方案 它比您将要查找的要容易(很难找到并且不再支持许多解决方案,许多其他解决方案提供了文件的路径,而不是实际目录),并且已证明可以在1.12版上使用。

new File(".").getCanonicalPath()

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

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

两者都将返回以下格式的字符串:

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

简洁明了。

答案 17 :(得分: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上运行良好

答案 18 :(得分:2)

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

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

答案 19 :(得分: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");
}

答案 20 :(得分:1)

对其他人不太确定,但在我的情况下,它不能与“Runnable 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");

答案 21 :(得分: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);

答案 22 :(得分:0)

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


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

答案 23 :(得分: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);
  } 

来自Determine if running from JAR

的代码

答案 24 :(得分: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;
    }

答案 25 :(得分: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;
  }

答案 26 :(得分:0)

尝试一下:

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

答案 27 :(得分: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;
        }
    }
}

答案 28 :(得分:-1)

对于一些愚蠢的简单事情,您只需要这一行:

对于 Windows 用户,将“pwd”更改为“cd”

runCommand("pwd");

然后把这个方法扔到类中:

public static String runCommand(String command) {
    StringBuilder sb = new StringBuilder();
    try {
        ProcessBuilder pb = new ProcessBuilder(command);
        final Process p = pb.start();
        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        sb.append(br.read());
        while ((line= br.readLine()) != null) sb.append(line).append("\n");
    }
    catch (IOException e) {e.printStackTrace();}
    return sb.toString();
}

答案 29 :(得分:-1)

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

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

输出字符串的格式为

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

处理空格和其他字符,格式为file:/。所以会更容易使用。

答案 30 :(得分:-1)

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

答案 31 :(得分:-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上进行测试