/**
* 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);
}
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);
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);
}
25条答案
按热度按时间iyzzxitl16#
不太清楚其他的,但在我的例子中,它不适用于“runnable jar”,我通过修复phchen2 answer中的代码和这个链接中的另一个代码来实现它:如何获得运行jar文件的路径?代码:
1cklez4t17#
获得
File
对于给定的Class
,有两个步骤:转换
Class
到URL
转换URL
到File
重要的是要理解这两个步骤,而不是混为一谈。一旦你有了
File
,您可以拨打getParentFile
获取包含文件夹,如果您需要的话。步骤1:类到url
正如在其他答案中所讨论的,有两种主要的方法可以找到
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框架内执行时。相反地getProtectionDomain
正确的方法会产生file:
甚至可以从osgi内部访问url。请注意,两者
getResource("")
以及getResource(".")
当类驻留在jar文件中时,在我的测试中失败;两个调用都返回null。因此,我建议使用上面显示的#2调用,因为它看起来更安全。步骤2:文件的url
不管怎样,一旦你有了
URL
,下一步是转换为File
. 这是它自己的挑战;请参阅kohsuke kawaguchi的博客文章以了解详细信息,但简而言之,您可以使用new File(url.toURI())
只要url的格式完全正确。最后,我强烈反对使用
URLDecoder
. url的某些字符,:
以及/
特别是,不是有效的url编码字符。从URLDock:假设编码字符串中的所有字符都是以下字符之一:“a”到“z”、“a”到“z”、“0”到“9”以及“-”、“_u3;”、“和”*”。字符“%”是允许的,但被解释为特殊转义序列的开始。
...
这个解码器有两种可能的方法来处理非法字符串。它可以不使用非法字符,也可以抛出illegalargumentexception。解码器采用哪种方法取决于实现。
实际上,
URLDecoder
一般不扔IllegalArgumentException
如上所述。如果文件路径的空格编码为%20
,这种方法似乎可行。但是,如果文件路径有其他非字母数字字符,例如+
你会有问题的URLDecoder
损坏文件路径。工作代码
要实现这些步骤,可以使用以下方法:
您可以在scijava公共库中找到这些方法:
org.scijava.util.classutils文件
org.scijava.util.fileutils。
utugiqy618#
将“myclass”替换为类的名称。
显然,如果您的类是从非文件位置加载的,那么这样做会很奇怪。
mzsu5hc019#
我们已经尝试了几种解决方案,但是没有一种能够产生正确的结果(可能是特殊的),即在eclipse中,runnable jar是通过“打包外部库”导出的。出于某种原因,在这种情况下,所有基于protectiondomain的解决方案都会导致null。
通过结合上述一些解决方案,我成功地实现了以下工作代码:
zbdgwd5y20#
如果你真的在寻找一种简单的方法来获取你的jar所在的文件夹,你应该实现这种格式的解决方案,它比你要找到的要容易得多(很难找到,很多解决方案已经不受支持了,许多其他人提供文件的路径而不是实际的目录),这在版本1.12上已经被证明是有效的。
从其他答案中收集信息这也是一个简单的问题:
两者都将返回以下格式的字符串:
简洁明了。
dluptydi21#
实际上,这里有一个更好的版本-如果文件夹名中有空格,则旧版本失败。
至于小程序失败,您通常无法访问本地文件。我对jws了解不多,但要处理本地文件,可能无法下载应用程序。?
6bc51xsx22#
此方法从存档中的代码调用,返回.jar文件所在的文件夹。它应该在windows或unix中工作。
派生自代码:确定是否从jar运行
ohtdti5x23#
我的最佳解决方案:
这应该可以解决空格和特殊字符的问题。
vtwuwzda24#
在linux、mac和windows上唯一适合我的解决方案是:
yquaqz1825#
最简单的解决方案是在运行jar时将路径作为参数传递。
可以使用shell脚本(在windows中为.bat,在其他任何地方为.sh)自动执行此操作:
我曾经
.
传递当前工作目录。更新
您可能希望将jar文件粘贴到子目录中,这样用户就不会意外地单击它。您的代码还应该检查以确保提供了命令行参数,如果缺少参数,则提供良好的错误消息。