代码之家  ›  专栏  ›  技术社区  ›  heapyams

Java可执行文件无法读取资源文件夹[重复]

  •  -2
  • heapyams  · 技术社区  · 2 年前

    我现在有一段时间在与这个问题作斗争,我想问你们中是否有人有使用可执行文件中的Java资源文件的经验。

    我有一个java应用程序构建,maven直接将jar转换为exe。

    pom.xml

    <build>
            <resources>
                <resource>
                    <directory>${basedir}/src/main/resources</directory>
                    <includes>
                        <include>**/*</include>
                    </includes>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.11.0</version>
                    <configuration>
                        <source>20</source>
                        <target>20</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.openjfx</groupId>
                    <artifactId>javafx-maven-plugin</artifactId>
                    <version>0.0.8</version>
                    <executions>
                        <execution>
                            <!-- Default configuration for running with: mvn clean javafx:run -->
                            <id>default-cli</id>
                            <configuration>
                                <mainClass>com.example.package/com.example.package.Main</mainClass>
                                <launcher>${project.artifactId}</launcher>
                                <jlinkZipName>${project.artifactId}</jlinkZipName>
                                <jlinkImageName>${project.artifactId}</jlinkImageName>
                                <noManPages>true</noManPages>
                                <stripDebug>true</stripDebug>
                                <noHeaderFiles>true</noHeaderFiles>
                                <compress>2</compress>
                            </configuration>
                            <phase>package</phase>
                            <goals>
                                <goal>jlink</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>3.0.0</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>exec</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <executable>${project.basedir}\tools\warp-packer.exe</executable>
                        <arguments>
                            <argument>--arch</argument>
                            <argument>windows-x64</argument>
    
                            <argument>--input_dir</argument>
                            <argument>${project.build.directory}\${project.artifactId}</argument>
    
                            <argument>--exec</argument>
                            <argument>bin\${project.artifactId}.bat</argument>
    
                            <argument>--output</argument>
                            <argument>${project.build.directory}\${project.artifactId}.exe</argument>
                        </arguments>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    

    该代码包含一个试图读取资源文件夹中所有文件的函数:

    public static String [] getFiles(){
        String[] outStrings = new File(Utillity.class.getResource("files").getPath()).list();
        System.out.println(Arrays.toString(out_strings));
        return outStrings;
    }
    

    此函数导致异常以exe形式执行,因为 getResource("files") 返回null。在IDE中,一切都很好。

    经过调查,我发现因为我在罐子环境中工作,所以我必须小心处理文件。

    看了几眼之后 tutorials 我试着找出一条全球路径。这失败了。例如,此代码:

    String jarPath = CallingPythonScripts.class
        .getProtectionDomain()
        .getCodeSource()
        .getLocation()
        .toURI()
        .getPath();
    System.out.println("JAR Path : " + jarPath);
    
    // Get name of the JAR file
    String jarName = jarPath.substring(jarPath.lastIndexOf("/") + 1);
    System.out.println("JAR Name: " + jarName);
    

    提供了以下输出:

    JAR Path: /com.example.package
    JAR Name: com.example.package
    

    我也知道必须有某种可行的解决方案,因为以下代码提供了与“files”文件夹处于同一文件夹层次级别的测试文件的内容:

    InputStream is = CallingPythonScripts.class.getResourceAsStream("demo.txt");
    
    try (
       InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
       BufferedReader br = new BufferedReader(isr)) {
    
           br.lines().forEach(line -> System.out.println(line));
    }catch (IOException e){
        e.printStackTrace();
    }
    

    此外,可读的不是“demo.txt”,而是“files/demo2.txt”。对于文件夹本身,它返回null。

    我确信这与内部文件表示形式有关。此外,在IDE中,一切都很正常,只是执行exe导致了这种情况。

    1 回复  |  直到 2 年前
        1
  •  0
  •   rzwitserloot    2 年前

    new File(Utillity.class.getResource("files").getPath()).list();

    这是你的问题。 不能列出资源,句号。

    一个严重的问题是,如果您的资源没有被打乱,那么上面的代码工作得很好。更稳健地采用了这一想法,甚至可以在某些平台上使用(在某些平台中,您试图获得一个目录作为资源并打开它,在某些平台上将获得一个列表),但是 不支持 -规范中没有提到类加载器必须支持这一点,事实上,很多都不支持。

    结论很简单: 无法列出资源 。如果你遇到一个说可以的图书馆,那就是在撒谎:充其量,这是一种只在特定条件下有效的黑客攻击。

    标准的解决方法是您应该使用的服务装载机。

    该概念的工作原理如下:

    • 程序员要么手工编写,要么使用构建系统插件,最终得到一个包含您感兴趣的列表的文本文件。然后,该文本文件将包含在硬编码路径中。
    • 然后加载应用程序 那个文本文件 -这很好。资源系统无法列出目录的内容。但是,在已知位置为您提供文本文件的全部内容是没有问题的。
    • 然后,该列表用于加载您需要加载的任何内容。

    甚至有一个被烘焙到java中的类可以做到这一点: ServiceLoader 。你应该在网上搜索这个术语的教程,你会发现很多。

    有很多图书馆和博客文章试图解决这个问题。例如,有些人将资源作为URL获取,然后尝试解析这些资源,例如打开jar文件。问题是,ClassLoader系统完全是抽象的。ClassLoader可以从网络加载资源,动态解密它们,或者将它们组成整体。 而且它们不必支持作为基元列出 因此,任何这样的尝试都是不完整的。使用服务加载程序范例,因为这是“完整的”——无论类加载程序实现如何,它都能工作。