简体   繁体   English

java jar - 如何指定应保存资源的位置?

[英]java jar - how do I specify where resources should be saved?

Here's my current pom.xml :这是我当前的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hu.elte.inf</groupId>
    <artifactId>ThesisMVN</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
            <plugin>
                <!-- Build an executable JAR -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>main/Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.javatuples</groupId>
            <artifactId>javatuples</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
</project>

I need the structure of my resources folder (and its subfolders) maintained, as currently takes them out of resources folder, so my game can't start because it can't find all the textures.我需要维护我的资源文件夹(及其子文件夹)的结构,因为目前将它们从资源文件夹中取出,所以我的游戏无法启动,因为它找不到所有纹理。
resource structure within the project项目内的资源结构
项目内的资源结构
jar-ed resource structure (note that only one effects folder is in the jar, it put the images next to the class file here) jar-ed 资源结构(注意 jar 中只有一个effects文件夹,它将图像放在 class 文件旁边)
压缩资源结构

Here's how I'm currently loading Images这是我目前加载图片的方式

public class ResourceLoader {
    public static Image getResource(String path){
        Image img=null;
        try{
           img = ImageIO.read(new File(path));
        }
        catch(IOException e) {
            System.err.println("File not found("+path+')');
            e.printStackTrace();
        }
        return img;
    }
}

The path passed to getResource is acquired from an enum where I set the path of all of my Images, like this:传递给 getResource 的path是从一个枚举中获取的,我在其中设置了所有图像的路径,如下所示:

...
BULLET("src/main/resources/bullet.png"),
BULLET_GREY("src/main/resources/bullet_grey.png"),
...
AOE_SLOW("src/main/resources/effects/aoeSlow.png"),
AOE_DISARM("src/main/resources/effects/aoeDisarm.png"),
...

I assume I should drop the src/main/resources prefixes, but then I can onyl reach the Images once the project is jarred up.我假设我应该删除src/main/resources前缀,但是一旦项目被破坏,我就只能到达图像。

This may be the wonky part of my setup but I'm currently storing every loaded Image in a class called GameStateData .这可能是我的设置中不稳定的部分,但我目前将每个加载的图像存储在一个名为GameStateData的 class 中。 Whenever I need to create a new Sprite I just get the already loaded Image from there, so I only need to load every Image just once when launching the game.每当我需要创建一个新的Sprite时,我只是从那里获取已经加载的图像,所以我只需要在启动游戏时加载每个图像一次。

I need the structure of my resources folder (and its subfolders) maintained我需要维护资源文件夹(及其子文件夹)的结构

It IS maintained.得到维护。 Every file and directory in your resources folder has been dutifully copied straight into the jar as the Standard Directory Layout dictates.按照标准目录布局的规定,资源文件夹中的每个文件和目录都已尽职尽责地直接复制到 jar 中。

The problem is your setup: At 'dev time' you appear to attempt to load from resources/items/someItem.png and this doesn't work when your app is jarred up.问题是您的设置:在“开发时间”,您似乎试图从resources/items/someItem.png加载,当您的应用程序出现问题时,这不起作用。 There are 2 obvious ways this can be happening;有两种明显的方式可以发生这种情况;

You're confused about the reason你对原因感到困惑

You're trying to use new FileInputStream , new File , or otherwise are attempting to load these as files .您正在尝试使用new FileInputStreamnew File或以其他方式尝试将它们作为文件加载。 This does not work and cannot work and no amount of futzing with directory structures will ever make it work.这行不通,也行不通,对目录结构进行再多的调整也无法使其发挥作用。 In java, file means file - and a png entry in a jarfile is not itself a file.在 java 中,file 表示文件- jarfile 中的 png 条目本身不是文件。

The way to load such resources is, always, this strategy:加载此类资源的方式始终是这种策略:

  1. Pick a class that is the 'source location' - as in, the resource you're looking for will be where-ever the JVM found this class file.选择一个 class 作为“源位置” - 例如,您要查找的资源将位于 JVM 找到此 class 文件的任何位置。 Generally you can pick any class in your entire application;一般来说,你可以在整个应用程序中选择任何一个 class; this is relevant only when you use modularized class loading systems.这仅在您使用模块化 class 装载系统时才有意义。 If you don't know what that means, you're not using those.如果您不知道那是什么意思,那么您就没有使用它们。

  2. Call MyContextClass.class.getResource(resourceKey) to obtain a URL object, which you can then pass to whatever API allows you to do that (and lots of APIs do, notably including swing's own ImageIcon ).调用MyContextClass.class.getResource(resourceKey)以获得 URL object,然后您可以将其传递给任何 API 允许您执行此操作的对象(许多 API 都这样做,特别是包括 swing 自己的ImageIcon )。 Alternatively, use try (var in = MyContextClass.class.getResourceAsStream(resourceKey) { /* use resource here */ } - this is the one to use if the API in question doesn't have an overload that takes a URL but does have one that takes an InputStream. This is also the one to use if you want to directly read the contents.或者,使用try (var in = MyContextClass.class.getResourceAsStream(resourceKey) { /* use resource here */ } - 如果所讨论的 API 没有采用 URL 的重载但确实有一个接受 InputStream 的。如果你想直接读取内容,这也是使用的一个。

  3. resourceKey comes in 2 flavours. resourceKey有两种风格。 There's "foo/bar.png" which resolves a path relative to the exact package your context class is in. If you have package com.foo; public class Bar {}"foo/bar.png" ,它解析了一个相对于你的上下文 class 所在的确切package的路径。如果你有package com.foo; public class Bar {} package com.foo; public class Bar {} then somewhere in the deployment there's com/foo/Bar.class . package com.foo; public class Bar {}然后在部署的某处有com/foo/Bar.class For example, in a jar file, or in a bin dir.例如,在 jar 文件中,或在bin目录中。 If you then write Bar.class.getResource("baz/quux.png") , and Bar.class was in that jar file, then the system is going to look in the same jar file, for com/foo/baz/quux.png .如果您随后编写Bar.class.getResource("baz/quux.png") ,并且 Bar.class 在该 jar 文件中,那么系统将在同一个 jar 文件中查找com/foo/baz/quux.png Alternatively, include a leading slash: "/foo/bar.png" would look in the same jar, but for foo/bar.png .或者,包括一个前导斜杠: "/foo/bar.png"将在相同的 jar 中查找,但对于foo/bar.png

  4. That's all you have to do.这就是你所要做的。 Build systems and IDEs ensure that you put your images exactly where you have them now (in a resources folder), you do not include resources in your deployment key (for the same reason you have your java source files in src/main/java/com/foo/MyApp.class , and you do not include src , main , or java in your fully qualified class names. It's just com.foo.MyApp , not main.java.com.foo.MyApp . The resources isn't a part of it any more than java is a part of your class names. If it doesn't work you've misconfigured them.构建系统和 IDE 确保您将图像准确地放置在您现在拥有它们的位置(在resources文件夹中),您不在部署密钥中包含resources (出于同样的原因,您将 java 源文件放在src/main/java/com/foo/MyApp.class ,并且您在完全限定的 class 名称中不包含srcmainjava 。它只是com.foo.MyApp ,而不是main.java.com.foo.MyApp resources其中java是您的 class 名称的一部分。如果它不起作用,则说明它们配置错误。

You've got a wonky setup你有一个不稳定的设置

It's possible you've been hacking away and eg using a plugin system where you check for certain files either directly on the filesystem yourself, -OR- load via ContextClass.class.getResource , or you've been messing with the way your IDE's maven plugin identifies resource directories, or you've been handrolling the setup of your IDE projects (instead of using its maven integration) and marked src/main as source dir (instead of src/main/java and src/main/resources ).有可能你一直在黑客攻击,例如使用一个插件系统,你可以自己直接在文件系统上检查某些文件, - 或者 - 通过ContextClass.class.getResource加载,或者你一直在搞乱你的 IDE 的方式 maven插件标识资源目录,或者您一直在手动设置 IDE 项目(而不是使用其 maven 集成)并将src/main标记为源目录(而不是src/main/javasrc/main/resources )。 The setup is broken;设置坏了; fix that (do not 'fix' it by trying to keep resources around).修复它(不要通过尝试保留resources来“修复”它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM