访问资源文件的 Maven 问题

Maven Issue With Accessing Resource File

我正在尝试使用 Maven 构建一个 JAR 文件,该文件将在 运行 时间内从文件系统加载文件。使用

编译后加载文件时遇到问题
 mvn clean package

pom.xml:

<build>
    <resources>
        <resource>
            <filtering>true</filtering>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>App</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>7</source>
                <target>7</target>
            </configuration>
        </plugin>
    </plugins>
</build>

我的主要 Class 是:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class App {
    public static void main(String[] args) throws IOException {
        App app = new App();
        app.printTestFile();
    }

    public void printTestFile() throws IOException {
        File file = new File(getClass().getClassLoader().getResource("template.txt").getFile());
        System.out.println("File is in " + file.getAbsolutePath());
        printFile(file);
    }

    private static void printFile(File file) throws IOException {
        try (FileReader reader = new FileReader(file);
             BufferedReader br = new BufferedReader(reader)) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

文件载入:

File file = new File(getClass().getClassLoader().getResource("template.txt").getFile());

项目结构为:

│   pom.xml
└───src
    ├───main
    │   ├───java
    │   │       App.java
    │   └───resources
    │           template.txt
    └───test
        └───java

当 运行 使用 IntelliJ 时,结果是:

File is in C:\Users\user\Documents\Git\maven-scratch\target\classes\template.txt
This is the test file's content.

但是,当 运行 完全使用 Maven 时,问题就来了,例如:

mvn clean package
java -jar target\maven-scratch-1.0-SNAPSHOT.jar

输出错误:

File is in C:\Users\user\Documents\Git\maven-scratch\file:\C:\Users\user\Documents\Git\maven-scratch\target\maven-scratch-1.0-SNAPSHOT.jar!\template.txt
Exception in thread "main" java.io.FileNotFoundException: file:\C:\Users\user\Documents\Git\maven-scratch\target\maven-scratch-1.0-SNAPSHOT.jar!\template.txt (The filena
me, directory name, or volume label syntax is incorrect)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(Unknown Source)
        at java.io.FileInputStream.<init>(Unknown Source)
        at java.io.FileReader.<init>(Unknown Source)
        at App.printFile(App.java:19)
        at App.printTestFile(App.java:15)
        at App.main(App.java:9)

最让我困惑的是试图加载的文件具有路径:

C:\Users\user\Documents\Git\maven-scratch\file:\C:\Users\user\Documents\Git\maven-scratch\target\maven-scratch-1.0-SNAPSHOT.jar!\template.txt

...是否使用 IntelliJ 路径是:

C:\Users\user\Documents\Git\maven-scratch\target\classes\template.txt

有没有一种简单的方法可以使用 Maven 的资源文件夹中的文件,并在使用 Maven 打包到 JAR 后也能够从目标目录中读取文件?

使用maven assembly plugin生成目标jar可以帮助您解决这个问题。 maven assembly

JAR 结构很好(通过将其加载到 zip 文件查看器中可以轻松验证)。

IntelliJ 的类路径是 本地文件系统 - 它正在加载一个真实的文件 ./target/classes/template.txt

命令行类路径在 JAR 文件 (maven-scratch-1.0-SNAPSHOT.jar!\template.txt) 中寻找相同的东西。这不是实际文件本身,它是 JAR 文件 中的一些字节。基本上它不能被 FileReader 读取,它正在寻找一个字面上名为 maven-scratch-1.0-SNAPSHOT.jar!\template.txt

的文件
    // getResourceAsStream doesn't care if it comes from a real file or a jar
    InputStream is = getClass().getClassLoader().getResourceAsStream("fix.cfg");
    InputStreamReader reader = new InputStreamReader(is);