0

I'm trying to familiarize myself with maven and created a test project for that purpose. I created a simple class, which just prints some stuff, read from a .txt file. My main class looks like this:

public class HelloWorld {
    public static void main(String[] args) throws IOException {
        String filePath = HelloWorld.class.getClassLoader().getResource("test.txt").getFile();

        BufferedReader br = new BufferedReader(new FileReader(filePath));
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }
}

I created a resource folder, marked it as resource root, modified the resource pattern and packaged a executeable jar from my project. My project structure looks like this:

Quickstart
├───.idea
├───src
│   ├───main
│   │   ├───java
│   │   │   └───de
│   │   │       └───mb
│   │   │           └───hello
|   |   |               └───HelloWorld.java
│   │   └───resources
|   |       └───test.txt

Now my problem is that, when I try to execute my jar I get the following error:

Exception in thread "main" java.io.FileNotFoundException:   
file:\C:\Users\mb\IdeaProjects\Quickstart\target\Quickstart-1.
0-SNAPSHOT.jar!\test.txt (The filename, directory name, or volume label syntax is incorrect)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at java.io.FileReader.<init>(FileReader.java:58)
    at de.mb.hello.HelloWorld.main(HelloWorld.java:15)

I guess the problem is, that the .txt file is inside the .jar, but how should I declare the path to make it work? I already tried using different ways to get my resource path to no avail and modified my pom.xml:

<project>
    ...
    <build>
        <resources>
            <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.txt</include>
            </includes>
            </resource>
        </resources>
        ...
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>3.2.0</version>
                    <configuration>
                    <transformers>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <manifestEntries>
                            <Main-Class>de.mb.hello.HelloWorld</Main-Class>
                        </manifestEntries>
                        </transformer>
                    </transformers>
                    </configuration>
                    <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Update: As suggested, I changed my code to use getResourceAsStream() instead of getResource() and it works, like so:

public static void main(String[] args) {
    try {
        InputStream in = HelloWorld.class.getClassLoader().getResourceAsStream("test.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        try {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } finally {
            in.close();
            br.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
MaikB
  • 115
  • 7

1 Answers1

1

The resource packaged in your jar file is not a File but a series of bytes in a zip file. It must be processed has a stream of bytes.

Use getResourceAsStream(...) instead of getResource(...) to get an InputStream instead of File and read the content with an InputStreamReader instead of FileReader.

Don't forget to close resources in a finally block or with a try-with-resources.

Something like that :

public class HelloWorld {
    public static void main(String[] args) throws IOException {
        try(BufferedReader br = new BufferedReader(new InputStreamReader(HelloWorld.class.getClassLoader().getResourceAsStream("test.txt")))) {
          String line;
          while ((line = br.readLine()) != null) {
              System.out.println(line);
          }
       }
    }
}
Sébastien Helbert
  • 2,185
  • 13
  • 22