如何获得正在运行的JAR文件的path?

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

所以,如果foo.jar在C:\FOO\ ,无论我当前的工作目录是什么,我都想得到这个path。

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

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

最适合我的解决scheme:

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

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

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

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

理解这两个步骤是非常重要的,不要混淆它们。

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

第1步:到URL Class

正如在其他答案中所讨论的那样,有两种主要方法可以find一个与Class有关的URL

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

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

两者都有优点和缺点。

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

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

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

第2步:到File URL

无论哪种方式,一旦你有一个URL ,下一步是转换为File 。 这是自己的挑战; 看到Kohsuke Kawaguchi关于它的博客文章的全部细节,但总之,只要URL是完整格式的,你就可以使用new File(url.toURI())

最后,我会极力劝阻使用URLDecoder 。 URL的某些字符:/尤其不是有效的URL编码字符。 从URLDecoder Javadoc:

假定编码string中的所有字符是下列之一:“a”到“z”,“A”到“Z”,“0”到“9”和“ – ”,“_”,“ 。“和”*“。 字符“%”是允许的,但被解释为特殊转义序列的开始。

有两种解码器可以处理非法string的方法。 它可能会留下非法字符,也可能会抛出IllegalArgumentException。 解码器采用哪种方法留给实现。

实际上, URLDecoder通常不会像上面那样引发IllegalArgumentException 。 而如果你的文件path的空间编码为%20 ,这种方法可能似乎工作。 但是,如果您的文件path具有其他非字母数字字符(例如+那么URLDecoder会改变文件path。

工作代码

要实现这些步骤,可能需要如下的方法:

 /** * Gets the base location of the given class. * <p> * If the class is directly on the file system (eg, * "/path/to/my/package/MyClass.class") then it will return the base directory * (eg, "file:/path/to"). * </p> * <p> * If the class is within a JAR file (eg, * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the * path to the JAR (eg, "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 eg {@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 eg {@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公共库中find这些方法:

  • org.scijava.util.ClassUtils
  • org.scijava.util.FileUtils 。

你也可以使用:

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

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

(这个例子来自一个类似的问题 。)

要find该目录,您需要手动拆分url。 请参阅JarClassLoader教程 ,了解jar URL的格式。

我很惊讶地发现最近没有人提出使用Path 。 这里有一个引用:“ Path类包括各种方法,可用于获取有关path的信息,path的访问元素,将path转换为其他窗体或提取path的一部分

因此,一个很好的select是把Path目标定为:

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

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

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

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

相反,我喜欢以下的解决scheme在任何地方工作:

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

我有同样的问题,我解决这个问题:

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

我希望我对你有所帮助。

这里升级到其他评论,这对我来说似乎是不完整的

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

为了获得正在运行的jar文件的path,我研究了上述的解决scheme,尝试了所有存在一些差异的方法。 如果这些代码在Eclipse IDE中运行,它们都应该能够find包含指定类的文件的path,并打开或创build一个指定的文件与find的path。

但是,当直接运行可执行jar文件或者通过命令行运行时,这是非常棘手的,因为从上面的方法获得的jar文件的path会在jar文件中给出一个内部path,所以它会失败,如

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

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

获得在Eclipse IDE之外运行jar文件的path的唯一可能的方法是

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

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

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

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

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

该path始终是指jar文件中的资源。

我试图让jar运行path使用

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

c:\ app> java -jar application.jar

运行名为“application.jar”的jar应用程序,在文件夹“ c:\ app ”的Windows中,stringvariables“folder”的值是“ \ c:\ app \ application.jar ”path的正确性

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

所以我试图把“testing”定义为:

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

以“ c:\ app ”而不是“ \ c:\ app \ application.jar ”的正确格式获得path,我注意到它的工作原理。

最简单的解决scheme是在运行jar时将path作为parameter passing。

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

 java -jar my-jar.jar . 

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

UPDATE

您可能希望将jar文件粘贴到子目录中,以便用户不会意外地点击该文件。 您的代码还应该检查以确保命令行参数已经提供,并提供一个很好的错误消息,如果参数丢失。

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

使用

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

在我终于find一个工作(和简短)的解决scheme之前,我不得不瞎搞。
jarLocation可能带有前缀,如file:\jar:file\ ,可以使用String#substring()来删除。

 URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation(); String jarLocation = new File(jarLocationUrl.toString()).getParent(); 
 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上运行良好

一些令人沮丧的事情是,当你在Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()返回非常好的/bin目录时,当你编译到jar时,path包含/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"); } 

不太确定其他人,但在我的情况下,它没有与“Runnable jar”工作,我得到它通过从phchen2答案和另一个链接固定代码工作: 如何获得正在运行的JAR文件的path? 代码:

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

提到它只在Windows检查,但我认为它适用于其他操作系统[ Linux,MacOs,Solaris ] :)。


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

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


警告!

  • 下面似乎工作得很好,我已经完成了所有的testing文件夹名称;][[;'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 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; } 

这段代码适用于我:

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

忽略备份小伙子的答案,它可能有时看起来不错,但有几个问题:

这里应该是+1不是-1:

 name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' '); 

非常危险,因为如果path没有空格,并不是立即显而易见的,但是replace“%”将会在每个空白处留下一堆20:

 name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' '); 

对于白色空间来说,有比循环更好的方法。

也会在debugging时造成问题。

从存档中的代码调用此方法将返回.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运行

我用Java 7编写,在Windows 7中用Oracle运行时testing,Ubuntu用开源运行时testing。 这对于那些系统是完美的:

任何正在运行的jar文件的父目录path(假设调用此代码的类是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的path是:

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

再次,这是没有在任何Mac或更旧的Windows上testing

getProtectionDomain方法有时可能无法正常工作,例如,当您必须为某些核心Java类(例如,在我的情况下,在IBM JDK中为StringBuilder类)findjar时,下面的工作可以无缝地进行:

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

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

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

输出string的forms是

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

处理空格和其他字符,并以不带file:/的formsfile:/ 。 所以会更容易使用。

或者你可以像这样传递当前的线程:

 String myPath = Thread.currentThread().getContextClassLoader().getResource("filename").getPath(); 

这一个class轮适用于包含空格或特殊字符(如ç或õ)的文件夹。 原来的问题要求绝对path(工作目录),没有JAR文件本身。 在Windows7上使用Java7进行testing:

 String workingDir = System.getProperty("user.dir"); 

参考: http : //www.mkyong.com/java/how-to-get-the-current-working-directory-in-java/