如何获取Java JAR文件中的资源路径

no_*_*ord 158 java resources path

我正试图找到资源的路径,但我没有运气.

这有效(在IDE和JAR中)但这样我无法获得文件的路径,只有文件内容:

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));
Run Code Online (Sandbox Code Playgroud)

如果我这样做:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());
Run Code Online (Sandbox Code Playgroud)

结果是: java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

有没有办法获得资源文件的路径?

小智 70

这是故意的."文件"的内容可能无法作为文件提供.请记住,您正在处理可能属于JAR文件或其他类型资源的类和资源.类加载器不必为资源提供文件句柄,例如,jar文件可能尚未扩展到文件系统中的单个文件中.

如果java.io.File是绝对必要的,那么通过将流复制到临时文件并执行相同的操作,可以通过获取java.io.File来完成任何操作.

  • 您可以在调用资源时添加'rsrc:'以打开它.像新文件("rsrc:filename.txt")这将加载filename.txt,它包装在你的jar的根目录中 (6认同)

Tom*_*art 57

加载资源时请务必注意以下两者之间的区别:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path
Run Code Online (Sandbox Code Playgroud)

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning
Run Code Online (Sandbox Code Playgroud)

我想,这种混乱在加载资源时会导致大多数问题.


此外,当您加载图像时,它更容易使用getResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));
Run Code Online (Sandbox Code Playgroud)

当您真的必须从JAR存档加载(非图像)文件时,您可以尝试这样做:

    File file = null;
    String resource = "/com/myorg/foo.xml";
    URL res = getClass().getResource(resource);
    if (res.getProtocol().equals("jar")) {
        try {
            InputStream input = getClass().getResourceAsStream(resource);
            file = File.createTempFile("tempfile", ".tmp");
            OutputStream out = new FileOutputStream(file);
            int read;
            byte[] bytes = new byte[1024];

            while ((read = input.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.close();
            file.deleteOnExit();
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
    } else {
        //this will probably work in your IDE, but not from a JAR
        file = new File(res.getFile());
    }

    if (file != null && !file.exists()) {
        throw new RuntimeException("Error: File " + file + " not found!");
    }
Run Code Online (Sandbox Code Playgroud)

  • +1这对我有用.确保将要读取的文件放在`bin`文件夹中,然后在使用`/com/myorg/filename.ext'路径之前转到资源中加载的类的目录. (3认同)

小智 25

一行答案是 -

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()
Run Code Online (Sandbox Code Playgroud)

基本上getResource方法给出了URL.通过此URL,您可以通过调用来提取路径toExternalForm()

参考文献:

getResource(), toExternalForm()

  • 从我的环境(IntelliJ)运行时,这会产生一个简单的文件URL,适用于所有情况.但是,当从jar本身运行时,我得到一个类似于jar的URI:file:/path/to/jar/jarname.jar!/file_in_jar.mp4.并非所有东西都可以使用以jar开头的URI.例如JavaFX Media. (6认同)
  • 我最喜欢这个答案。当然,在大多数情况下,当资源位于 jar 文件中时,最好简单地获取资源的 InputStream,但如果由于某种原因您确实需要该路径,那么这就是有效的方法。我需要提供给第三方对象的路径。那谢谢啦! (2认同)

小智 11

我花了一些时间来解决这个问题,因为我发现没有解决方案确实有效,奇怪的是!工作目录通常不是JAR的目录,尤其是在Windows下的"开始"菜单中运行JAR(或任何程序)时.所以这就是我所做的,它适用于从JAR外部运行的.class文件,以及它适用于JAR.(我只在Windows 7下测试过它.)

try {
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.

    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
    try {
        PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
    } catch (Exception e) { }

    //Find the last / and cut it off at that location.
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
    //If it starts with /, cut it off.
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
    //If it starts with file:/, cut that off, too.
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
    PROGRAM_DIRECTORY = ""; //Current working directory instead.
}
Run Code Online (Sandbox Code Playgroud)


cd1*_*cd1 8

如果netclient.p在JAR文件中,它将没有路径,因为该文件位于其他文件中.在这种情况下,你可以拥有的最佳途径是file:/path/to/jarfile/bot.jar!/config/netclient.p.


Bru*_*uce 8

这是来自用户 Tombart 的相同代码,带有流刷新和关闭,以避免从 jar 资源复制不完整的临时文件内容并具有唯一的临时文件名。

File file = null;
String resource = "/view/Trial_main.html" ;
URL res = getClass().getResource(resource);
if (res.toString().startsWith("jar:")) {
    try {
        InputStream input = getClass().getResourceAsStream(resource);
        file = File.createTempFile(new Date().getTime()+"", ".html");
        OutputStream out = new FileOutputStream(file);
        int read;
        byte[] bytes = new byte[1024];

        while ((read = input.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        out.flush();
        out.close();
        input.close();
        file.deleteOnExit();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
} else {
    //this will probably work in your IDE, but not from a JAR
    file = new File(res.getFile());
}
         
Run Code Online (Sandbox Code Playgroud)


小智 6

您需要了解jar文件中的路径.
简单地说它是相对的.所以如果你有一个文件(myfile.txt),位于\src\main\resources目录下的foo.jar (maven样式).你可以这样称它:

src/main/resources/myfile.txt
Run Code Online (Sandbox Code Playgroud)

如果使用转储jar jar -tvf myjar.jar ,将在jar文件中看到输出和相对路径,并使用FORWARD SLASHES.


jmg*_*esc 5

就我而言,我使用了 URL 对象而不是 Path。

文件

File file = new File("my_path");
URL url = file.toURI().toURL();
Run Code Online (Sandbox Code Playgroud)

使用类加载器的类路径中的资源

URL url = MyClass.class.getClassLoader().getResource("resource_name")
Run Code Online (Sandbox Code Playgroud)

当我需要阅读内容时,可以使用以下代码:

InputStream stream = url.openStream();
Run Code Online (Sandbox Code Playgroud)

您可以使用 InputStream 访问内容。