如何获得正在运行的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");
这应该解决空间和特殊字符的问题。
要获得给定Class
的File
,有两个步骤:
- 将该
Class
转换为URL
- 将
URL
转换为File
理解这两个步骤是非常重要的,不要混淆它们。
一旦你有了File
,你可以调用getParentFile
来获取包含的文件夹,如果这是你所需要的。
第1步:到URL
Class
正如在其他答案中所讨论的那样,有两种主要方法可以find一个与Class
有关的URL
。
-
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
-
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/