6

每当在以感叹号结尾的目录中运行可执行 jar 时,getResourceAsStream 方法都会返回null

对于以下示例,我有一个 Eclipse 项目,其目录结构如下:

src\ (Source Folder)
    main\ (Package)
        Main.java
    res\ (Source Folder)
        images\
            Logo.png

我正在阅读 Logo.png 如下:

public static void main(String[] args) throws IOException {
    try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) {
        Image image = ImageIO.read(is);
        System.out.println(image);
    }   
}

2个测试用例见附件。首先,可执行 jar 从目录“D:\test123!@#”启动,没有任何问题。其次,可执行jar是从目录“D:\test123!@#!!!”启动的,有问题。

是否不支持以感叹号结尾的目录?代码错了吗?

提前致谢。

在以 ! 结尾的目录中运行可执行 jar 时出错

4

2 回答 2

8

可能是因为这个错误或 Java 错误数据库中的许多类似错误:

http://bugs.sun.com/view_bug.do?bug_id=4523159

原因是 jar URL 中的“!/”被解释为 JAR 文件名和 JAR 本身中的路径之间的分隔符。如果目录名称以 ! 结尾,则目录末尾的“!/”字符序列将被错误解释。在您的情况下,您实际上是在尝试使用以下 URL 访问资源:

jar:file:///d:/test1231@#!!!/test.jar!/images/Logo.png

该错误已经开放了将近 12 年,并且不太可能被修复。其实我不知道如何在不破坏其他东西的情况下修复它。问题是使用的设计决定!作为 JAR 文件的 URL 方案中具有特殊含义的字符(分隔符):

jar:<URL for JAR file>!/<path within the JAR file>

由于感叹号是 URL 中允许的字符,它可能出现在 JAR 文件本身的 URL 中以及 JAR 文件中的路径中,因此在某些情况下无法找到实际的“!/”分隔符.

于 2013-07-04T09:22:47.667 回答
1

Windows 的一个简单解决方法是在路径中使用“\”而不是“/”。这意味着在完整路径之后找到“!/”字符序列。例如:

new URL("jar:file:\\d:\\test1231@#!!!\\test.jar!/images/Logo.png");

我的代码:

File jar = new File(jarPath + "/" + jarName);
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath);
InputStream stream = null;
try {
    stream = url.openStream();
} catch (FileNotFoundException e) {
    // Windows fix
    URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\')
        + "!" + dataFilePath);
    stream = urlFix.openStream();
}

我使用 toURI() 因为它处理诸如空格之类的事情。

修复:

修复本身将让 Java 检查文件是否存在,如果不继续到下一个分隔符(url 的“!/”部分),直到分隔符用完,然后抛出异常。所以它会看到“d:\test1231@#!!” 抛出 java.io.FileNotFoundException 然后会尝试确实存在的“d:\test1231@#!!!\test.jar”。这样,是否有“!”都没有关系 在文件路径或 jar 文件中。

或者,可以将“!/”切换为非法文件名或特定名称(如“jarpath:”)。

或者使 jar 的文件路径使用另一个参数。

笔记:

可能会覆盖某些东西,交换处理程序,或更改代码以先打开文件,然后再查看 jar 文件,但我没有查看。

于 2015-02-13T19:43:44.437 回答