为什么我的URI不是层次结构的?

73

我有一些文件在资源文件夹中。例如,如果我需要从资源文件夹中获取一个文件,我会这样做:

File myFile= new File(MyClass.class.getResource(/myFile.jpg).toURI());             
System.out.println(MyClass.class.getResource(/myFile.jpg).getPath());

我已经测试过,一切正常

路径为:

/D:/java/projects/.../classes/X/Y/Z/myFile.jpg

但是,如果我使用Maven创建jar文件:

mvn package

...然后启动我的应用程序:

java -jar MyJar.jar

我遇到了以下错误:

Exception in thread "Thread-4" java.lang.RuntimeException: ხელმოწერის განხორციელება შეუძლებელია
Caused by: java.lang.IllegalArgumentException: URI is not hierarchical
        at java.io.File.<init>(File.java:363)

...文件路径为:

file:/D:/java/projects/.../target/MyJar.jar!/X/Y/Z/myFile.jpg

当我尝试从资源文件夹获取文件时,出现了这个异常。就在这行代码。为什么?为什么在JAR文件中会有这个问题?你觉得呢?

是否有其他方法可以获得资源文件夹路径?


4
你可以看一下这个链接:https://dev59.com/3Wkw5IYBdhLWcg3wGGm8,以及被接受的回答。 - cyroxx
3个回答

109

你应该使用

getResourceAsStream(...);

当资源被捆绑成jar / war或任何其他单个文件包时.

问题在于,jar是一个单一的文件(有点像zip文件),它将许多文件放在一起。从操作系统的角度来看,它是一个单一的文件,如果您想要访问文件的一部分(例如图像文件),则必须将其用作流。

文档


12
能否将此转换为java.io.File类型? - Sip
我在 Docker 容器中遇到了同样的错误,但只有在 k8s 集群中运行时才会出现。在 IDE 或 Docker 容器中运行时,我没有这个错误。如果这有帮助... - Erick Audet
1
如果我想列出目录中的文件,使用它们的文件名,并将每个文件的文本单独读入Java对象中,该怎么办? - bonapart3
我用以下代码将其转换为文件: FileUtils.copyInputStreamToFile(inputStream, file); - Inanc Cakil

11

以下是适用于Eclipse RCP / 插件开发者的解决方案:

Bundle bundle = Platform.getBundle("resource_from_some_plugin");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
   URL resolvedFileURL = FileLocator.toFileURL(fileURL);

   // We need to use the 3-arg constructor of URI in order to properly escape file system chars
   URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
   File file = new File(resolvedURI);
} catch (URISyntaxException e1) {
    e1.printStackTrace();
} catch (IOException e1) {
    e1.printStackTrace();
}

使用FileLocator.toFileURL(fileURL)而不是resolve(fileURL)非常重要,因为当插件被打包成jar文件时,这将导致Eclipse在临时位置创建一个未解压的版本,以便可以使用File访问该对象。例如,我猜Lars Vogel在他的文章中有一个错误 - http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/


3
谢谢,我欠你一杯啤酒,确实Vogella的文章需要更新。 - Vlad Ilie
这个解决方案似乎是平台相关的。 在IntelliJ中是否有一种方法可以实现类似的功能,而不必导入“org.eclipse.core.runtime.FileLocator”? - pwillemet
@Kwoinkwoin,是的,这个解决方案适用于Eclipse RCP插件开发人员。我建议尝试使用getResourceAsStream(...)方法。 - Ilya Buziuk
1
此解决方案不是平台无关的。 - dasAnderl ausMinga

3

我在公司做项目时遇到了同样的问题。首先,URI不是分层结构的问题可能是因为您使用/作为文件分隔符。

您必须记住,"/"适用于Windows,而从一个操作系统到另一个操作系统它会发生变化,在Linux中可能是不同的。因此,请使用File.seperator

因此,使用

this.getClass().getClassLoader().getResource("res"+File.separator+"secondFolder")

可能会删除非分层URI,但现在您可能会遇到空指针异常。我尝试了许多不同的方法,然后使用JarEntries类来解决它。

File jarFile = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
        String actualFile = jarFile.getParentFile().getAbsolutePath()+File.separator+"Name_Of_Jar_File.jar";
        System.out.println("jarFile is : "+jarFile.getAbsolutePath());
        System.out.println("actulaFilePath is : "+actualFile);
        final JarFile jar = new JarFile(actualFile);
        final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
        System.out.println("Reading entries in jar file ");
        while(entries.hasMoreElements()) {
            JarEntry jarEntry = entries.nextElement();
            final String name = jarEntry.getName();
            if (name.startsWith("Might Specify a folder name you are searching for")) { //filter according to the path
                System.out.println("file name is "+name);
                System.out.println("is directory : "+jarEntry.isDirectory());
                File scriptsFile  = new File(name);
                System.out.println("file names are : "+scriptsFile.getAbsolutePath());

            }
        }
        jar.close();

你必须明确指定jar文件的名称。因此,请使用此代码,它将为你提供jar文件夹中的目录和子目录。

如果您将包装从jar更改为其他压缩文件实现(如zip),会怎样呢?这可以工作吗?如果您正在构建一个库,用户将不使用jar包装,那该怎么办? - bonapart3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接