java jar classpath设置




如何获取正在运行的JAR文件的路径? (20)

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

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

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

所以,如果foo.jar在C:\FOO\ ,我想要得到那个路径,不管我当前的工作目录是什么。


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

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

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

警告!

  • 以下似乎在我所做的所有测试中工作得非常好,即使使用文件夹名称也是如此;][[;'57f2g34g87-8+9-09!2#@!$%^^&() or ()%&$%^@#它运作良好。
  • 我在下面使用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[ user] + bachden [ 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文件的路径,我研究了上述解决方案,并尝试了所有存在一些差异的方法。 如果这些代码在Eclipse IDE中运行,它们都应该能够找到包含指定类的文件的路径,并打开或创建一个包含找到路径的指定文件。

但是,当直接或通过命令行运行可运行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文件所在的文件夹。 它应该在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运行


你也可以使用:

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网址的格式,请参阅JarClassLoader教程


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

在我终于找到一个工作(和简短)解决方案之前,我不得不乱糟糟。
jarLocation可能带有一个前缀,如file:\jar:file\ ,它可以通过使用String#substring()来删除。

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();

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

  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不是-1:

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

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

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

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

它也会在调试时引起问题。


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

因此,一个很好的选择是使Path成为如下对象:

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

我有另一种获得类的字符串位置的方法。

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

输出字符串的形式是

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

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


我遇到了同样的问题,我解决了这个问题:

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

我希望我对你有所帮助。


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

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

最适合我的解决方案:

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

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


此代码适用于我:

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


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

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

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上运行良好


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

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





executable-jar