【问题标题】:Unable to open resources in directories which end with an exclamation mark (!)无法打开以感叹号 (!) 结尾的目录中的资源
【发布时间】:2013-07-04 09:06:13
【问题描述】:

每当在以感叹号结尾的目录中运行可执行 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 包吗?
  • 用户可以从他们文件系统的任何地方执行我的应用程序。 Windows 支持带有感叹号的目录。
  • @Andremoniy 是的,100% 确定
  • @mtk:包含文件系统支持的字符的名称不“正常”是否有原因?

标签: java resources classpath classloader javax.imageio


【解决方案1】:

可能是因为这个错误或 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 文件中的路径中,因此在某些情况下无法找到实际的“! /" 分隔符。

【讨论】:

  • 我认为它必须用 Java 做一些事情并通过“!/”解析 URL,但我简直不敢相信这会是一个错误。无论如何,有没有办法解决这个问题?
  • 不,正如我在链接到的错误中所指出的那样,对于这个问题没有简单的解决方法。
【解决方案2】:

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 文件,但我没有查看。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    相关资源
    最近更新 更多