提问人:heapyams 提问时间:11/12/2023 最后编辑:user207421heapyams 更新时间:11/12/2023 访问量:52
Java 可执行文件无法读取资源文件夹 [重复]
Java executable can not read resources folder [duplicate]
问:
我现在正在为这个问题苦苦挣扎一段时间,并想问一下你们中是否有人有使用可执行文件中的 Java 资源文件的经验。
我有一个使用 maven 直接将 jar 转换为 exe 的 java 应用程序构建。
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;
}
此函数会导致 Exception 作为 exe 执行,因为返回 null。在IDE中一切正常。getResource("files")
经过调查,我发现因为我是在 jar 环境中工作的,所以我必须小心处理文件。
在查看了几个教程后,我尝试找出全局路径。这失败了。例如,以下代码:
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();
}
此外,“files/demo2.txt”不是“demo.txt”,而是可读的。对于文件夹本身,它返回 null。
我很确定它与内部文件表示有关。同样在IDE中,一切正常,只是exe的执行导致了这种情况。
答:
new File(Utillity.class.getResource("files").getPath()).list();
这是你的问题。您不能 LIST 资源,句点。
一个严重的问题是,如果你的资源没有被破坏,上面的代码可以“正常工作”。这个想法更健壮,甚至在某些平台上也有效(你试图获取一个目录作为资源并打开它,在某些平台上你得到一个列表),但它不受支持 - 规范没有提到类加载器必须支持这一点,事实上,许多人不支持。
结论很简单:不可能列出资源。如果你遇到一个说它可以的库,那它就是在撒谎:充其量它只是一个只在特定条件下起作用的黑客。
标准的解决方法是您应该为此使用的 - Service Loaders。
该概念的工作原理如下:
- 程序员要么手动写出来,要么使用构建系统插件,最终得到一个包含您感兴趣的列表的文本文件。然后,此文本文件将包含在硬编码路径中。
- 然后,应用程序加载该文本文件 - 这很好。资源系统无法列出目录的内容。但是,在已知位置为您提供文本文件的完整内容没有问题。
- 然后,此列表用于加载您需要加载的任何内容。
甚至还有一个内置到 java 中的类可以做到这一点:.您应该在网络上搜索带有该术语的教程,您会发现很多。ServiceLoader
有很多库和博客文章试图解决这个问题。例如,有些人将资源作为 URL 获取,然后尝试解析这些资源,例如打开 jar 文件。问题是,ClassLoader 系统是完全抽象的。ClassLoader 可以从网络加载资源,动态解密它们,或者将它们整块布组成。而且它们不必支持作为基元列出。因此,任何此类尝试都是不完整的。使用服务加载器范式,因为它是“完整的”——无论类加载器实现如何,它都能工作。
评论