我的代码在一个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");
这应该解决空格和特殊字符的问题.
要获得File
给定的Class
,有两个步骤:
转换Class
为aURL
转换URL
为aFile
理解这两个步骤很重要,而不是将它们混为一谈.
一旦你有了File
,你可以打电话getParentFile
来获取包含文件夹,如果这是你需要的.
Class
到URL
正如其他答案中所讨论的,有两种主要方法可以找到与a URL
相关的方法Class
.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
两者都有利有弊.
该getProtectionDomain
方法产生类的基本位置(例如,包含JAR文件).但是,Java运行时的安全策略可能会SecurityException
在调用时抛出getProtectionDomain()
,因此如果您的应用程序需要在各种环境中运行,最好在所有环境中进行测试.
该getResource
方法生成类的完整URL资源路径,您将需要从该路径执行其他字符串操作.它可能是一条file:
路径,但它也可能是jar:file:
甚至更糟糕的东西,就像bundleresource://346.fwk2106232034:4/foo/Bar.class
在OSGi框架内执行一样.相反,即使在OSGi中,该getProtectionDomain
方法也能正确生成file:
URL.
请注意这两个getResource("")
和getResource(".")
在我的测试中失败了,上课的时候一个JAR文件中居住; 两个调用都返回null.所以我推荐上面显示的#2调用,因为它似乎更安全.
URL
到File
无论哪种方式,一旦你有了URL
,下一步就是转换为File
.这是它自己的挑战; 有关详细信息,请参阅Kohsuke Kawaguchi的博客文章,但简而言之,new File(url.toURI())
只要URL完全格式化,您就可以使用它.
最后,我强烈反对使用URLDecoder
.URL的某些字符,:
并且/
特别是无效的URL编码字符.从URLDecoder Javadoc:
假设编码的字符串中的所有字符是下列之一:"a"至"Z","A"到"Z","0"至"9",和" - ","_"," ."和"*".允许使用字符"%",但将其解释为特殊转义序列的开头.
...
这种解码器有两种可能的方式来处理非法字符串.它可能会单独留下非法字符,也可能会抛出IllegalArgumentException.解码器采用哪种方法留给实现.
在实践中,URLDecoder
一般不会IllegalArgumentException
像上面那样受到威胁.如果你的文件路径有空格编码%20
,这种方法似乎可行.但是,如果您的文件路径具有其他非字母数字字符,例如+
您将在URLDecoder
修改文件路径时遇到问题.
要实现这些步骤,您可能拥有以下方法:
/** * Gets the base location of the given class. ** 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"). *
** 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"). *
* * @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}. ** 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. *
* * @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.
您还可以使用:
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")); } }
(这个例子来自一个类似的问题.)
要查找目录,您需要手动拆分URL.有关jar URL的格式,请参阅JarClassLoader教程.
我很惊讶地看到最近没有提议使用Path
.这里如下引文:" 的Path
类包括可以用来获得关于所述路径信息的各种方法,该路径的接入元件,所述路径转换为其它形式的,或提取的路径的部分 "
因此,一个好的选择是将Path
目标视为:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
在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(); }
这是对其他评论的升级,对于我来说,这似乎是不完整的
使用.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"));
我有同样的问题,我解决了这个问题:
File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()); String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath(); String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");
我希望我对你有所帮助.
为了获得运行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中).
其他答案似乎指向代码源,它是Jar文件位置,而不是目录。
使用
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();