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

时间:2009-06-02 20:32:47

标签: java resources path

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

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

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

如果我这样做:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

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

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

17 个答案:

答案 0 :(得分:68)

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

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

答案 1 :(得分:53)

加载资源时,请务必注意以下几点之间的区别:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

我猜,这种混淆导致加载资源时出现大多数问题。


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

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

当您真的必须从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!");
    }

答案 2 :(得分:20)

一行答案是 -

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

基本上getResource方法提供了URL。 通过此URL,您可以通过调用toExternalForm()

来提取路径

参考文献:

getResource()toExternalForm()

答案 3 :(得分: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.
}

答案 4 :(得分:8)

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

答案 5 :(得分:6)

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

src/main/resources/myfile.txt

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

答案 6 :(得分:2)

文件是文件系统中文件的抽象,文件系统不知道JAR的内容是什么。

尝试使用URI,我认为有一个jar://协议可能对你的用户有用。

答案 7 :(得分:2)

这是来自用户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());
        }

答案 8 :(得分:2)

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

文件

File file = new File("my_path");
URL url = file.toURI().toURL();

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

URL url = MyClass.class.getClassLoader().getResource("resource_name")

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

InputStream stream = url.openStream();

您可以使用InputStream访问内容。

答案 9 :(得分:1)

以下路径适用于我:classpath:/path/to/resource/in/jar

答案 10 :(得分:1)

private static final String FILE_LOCATION = "com/input/file/somefile.txt";

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

getSystemResourceAsStream 获取此信息是最佳选择。通过获取输入流而不是文件或URL,可以在JAR文件中工作,并且可以单独使用。

答案 11 :(得分:1)

在你的jar的ressources文件夹(java / main / resources)中添加你的文件(我们假设你已经添加了一个名为 imports.xml 的xml文件),之后,如果你使用像波纹管一样的弹簧,你可以注射@Output

ResourceLoader

在tour函数内写下波纹管代码以加载文件:

@Autowired
private ResourceLoader resourceLoader;

答案 12 :(得分:1)

可能有点晚了,但是您可以使用我的库KResourceLoader从jar中获取资源:

File resource = getResource("file.txt")

答案 13 :(得分:0)

关注代码!

/ src / main / resources / file

streamToFile(getClass().getClassLoader().getResourceAsStream("file"))

public static File streamToFile(InputStream in) {
    if (in == null) {
        return null;
    }

    try {
        File f = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        f.deleteOnExit();

        FileOutputStream out = new FileOutputStream(f);
        byte[] buffer = new byte[1024];

        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }

        return f;
    } catch (IOException e) {
        LOGGER.error(e.getMessage(), e);
        return null;
    }
}

答案 14 :(得分:0)

也许此方法可用于快速解决。

public static String getResourcePath(String relativePath)
{
    String pathStr = null;
    URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
    String codeLoaction = location.toString();
    try{
        if (codeLocation.endsWith(".jar"){
            //Call from jar
            Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
            pathStr = path.toString();
        }else{
            //Call from IDE
            pathStr = <Class>.class.getClassLoader().getResource(relativePath).getPath();
        }
    }catch(URISyntaxException ex){
        ex.printStackTrace();
    }
    return pathStr;
}

答案 15 :(得分:0)

在jar文件中,资源绝对位于包层次结构中(不是文件系统层次结构)。因此,如果您有com.example.Sweet类加载名为“./default.conf”的资源,那么资源的名称将指定为“/com/example/default.conf”。

但如果它在一个罐子里,那么它不是一个文件......

答案 16 :(得分:0)

据说,这已经说明了加载资源的最佳方式,但如果您绝对必须有java.io.File引用,请尝试以下方法:

 URL url = null;
  try {
     URL baseUrl = YourClass.class.getResource(".");
     if (baseUrl != null) {
        url = new URL(baseUrl, "yourfilename.ext");
     } else {
        url = YourClass.class.getResource("yourfilename.ext");
     }
  } catch (MalformedURLException e) {
     // Do something appropriate
  }

这会为您提供java.net.URL,并且可以在java.io.File构造函数中使用。