How to get the path of a running JAR file?
我的代码运行在一个jar文件中,比如foo.jar,我需要知道代码中运行的foo.jar在哪个文件夹中。
所以,如果foo.jar在
1 2 | return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation() .toURI()).getPath(); |
将"myClass"替换为类的名称。
显然,如果类是从非文件位置加载的,那么这将做一些奇怪的事情。
最佳解决方案:
1 2 | String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath(); String decodedPath = URLDecoder.decode(path,"UTF-8"); |
这应该解决带有空格和特殊字符的问题。
要获得给定
理解这两个步骤很重要,不要把它们混为一谈。
一旦你有了
如其他答案中所讨论的,找到与
两者都有利弊。
注意,当类位于JAR文件中时,
不管怎样,一旦你有了一个
最后,我强烈反对使用
It is assumed that all characters in the encoded string are one of the following:"a" through"z","A" through"Z","0" through"9", and"-","_",".", and"*". The character"%" is allowed but is interpreted as the start of a special escaped sequence.
...
There are two possible ways in which this decoder could deal with illegal strings. It could either leave illegal characters alone or it could throw an IllegalArgumentException. Which approach the decoder takes is left to the implementation.
实际上,
要实现这些步骤,您可能有如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | /** * 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公共库中找到这些方法:
- org.scijava.util.classutils
- org.scijava.util.fileutils.
您还可以使用:
1 2 3 | CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource(); File jarFile = new File(codeSource.getLocation().toURI().getPath()); String jarDir = jarFile.getParentFile().getPath(); |
使用classloader.getresource()查找当前类的URL。
例如:
1 2 3 4 5 6 7 8 9 10 | package foo; public class Test { public static void main(String[] args) { ClassLoader loader = Test.class.getClassLoader(); System.out.println(loader.getResource("foo/Test.class")); } } |
(这个例子取自类似的问题。)
要找到目录,您需要手动拆分URL。有关jar url的格式,请参阅jarclassloader教程。
我很惊讶地看到最近没有人提议使用
因此,一个好的选择是让
1 | Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI()); |
唯一适用于Linux、Mac和Windows的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } |
以下是对其他评论的升级,在我看来,这些评论对于
using a relative"folder" outside .jar file (in the jar's same
location):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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")); |
我也有同样的问题,我用这种方式解决了它:
1 2 3 |
希望我能帮助你。
为了得到运行jar文件的路径,我研究了上述解决方案,并尝试了所有相互之间存在差异的方法。如果这些代码在Eclipse IDE中运行,那么它们都应该能够找到文件的路径,包括指定的类,并使用找到的路径打开或创建指定的文件。
但很棘手的是,当直接或通过命令行运行可运行的jar文件时,它将失败,因为从上述方法获得的jar文件路径将在jar文件中给出一个内部路径,也就是说,它总是给出一个路径作为
rsrc:项目名(也许我应该说它是主类文件的包名——指定的类)
我不能转换rsrc:…指向外部路径的路径,即当在Eclipse IDE外运行JAR文件时,它无法获取JAR文件的路径。
获取在Eclipse IDE外运行JAR文件的路径的唯一可能方法是
1 |
这个代码行可以返回正在运行的JAR文件的生存路径(包括文件名)(注意返回路径不是工作目录),因为Java文档和一些人说它将返回同一目录中所有类文件的路径,但是当我的测试在同一目录中包含许多JAR文件时,它只返回P。运行jar的路径(关于多路径问题,实际上它发生在Eclipse中)。
如果您通过从GNOME桌面环境(而不是从任何脚本或终端)单击JAR来运行JAR,则上面选择的答案将不起作用。
相反,我喜欢以下解决方案无处不在:
1 2 3 4 5 | try { return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(),"UTF-8"); } catch (UnsupportedEncodingException e) { return""; } |
最简单的解决方案是在运行jar时将路径作为参数传递。
您可以使用shell脚本(在Windows中为.bat,在其他任何地方为.sh)自动执行此操作:
1 | java -jar my-jar.jar . |
我用
更新
您可能希望将JAR文件粘贴到子目录中,这样用户就不会意外地单击它。您的代码还应该检查以确保已经提供了命令行参数,并在缺少参数时提供良好的错误消息。
实际上,这里有一个更好的版本——如果文件夹名中有空间,则旧版本会失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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不太了解,但要处理本地文件,可能无法下载该应用程序。
在我最终找到一个有效的(短期的)解决方案之前,我不得不到处乱转。可能
1 2 |
其他答案似乎指向代码源,即JAR文件位置,而不是目录。
使用
1 | return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile(); |
1 |
路径总是引用JAR文件中的资源。
我试着用
1 |
C:APP> Java-jar应用程序
运行名为"application.jar"的jar应用程序,在Windows的文件夹"c:app"中,字符串变量"folder"的值为"c:appapplication.jar",我在测试路径的正确性时遇到了问题。
所以我试图将"测试"定义为:
要获得正确格式的路径,如"c:app",而不是"c:appapplication.jar",我注意到它可以工作。
1 2 3 4 5 6 7 8 9 10 11 12 | 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
为了让代码在IDE中工作,并且一旦编译到JAR中,我使用以下代码:
1 2 3 4 5 6 7 8 9 | 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"); } |
已经尝试了上面的几个解决方案,但没有一个能产生正确的结果(可能是特殊的),即运行jar已经在Eclipse中通过"打包外部库"导出。出于某种原因,在这种情况下,所有基于ProtectionDomain的解决方案都会导致空值。
通过结合上面的一些解决方案,我成功地实现了以下工作代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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); |
对其他人不太确定,但在我的例子中,它不适用于"可运行的jar",我通过修复phchen2-answer和这个链接中的另一个代码来实现它:如何获取运行的jar文件的路径?代码:
1 2 3 4 5 6 7 |
提到它只在
我在同一个目录中有2个
问题是,当您从
Warnings!
- 在我做过的所有测试中,下面的内容似乎都很有效文件夹名为
;][[;'57f2g34g87-8+9-09!2#@!$%^^&() 或()%&$%^@# 的它运作良好。 - 我使用的
ProcessBuilder 如下:
?……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //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 |
??
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /** * 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; } |
此方法从存档中的代码调用,返回.jar文件所在的文件夹。它应该在Windows或Unix中工作。
1 2 3 4 5 6 7 8 | 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运行
此代码适用于我:
1 2 3 4 5 6 | 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; } |
我用Java 7编写,在Oracle的运行时在Windows 7中测试,而Ubuntu在开源运行时进行测试。这非常适合这些系统:
任何运行的JAR文件的父目录的路径(假定调用此代码的类是JAR存档本身的直接子目录):
1 2 3 4 5 6 | 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的路径是:
1 |
同样,这并没有在任何Mac或旧的Windows上测试过。
EDCOX1×3的方法有时可能不起作用,例如当您必须为一些核心Java类找到JAR(例如,在我的例子中,在IBM JDK中的EDCOX1,4类),但是无缝地遵循以下工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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,""); } |
我有另一种方法来获取类的字符串位置。
1 2 3 |
输出字符串的形式为
1 2 | C:\Users\Administrator ew Workspace\... |
空格和其他字符被处理,并以不带