0

Here is my simple app that I am reading a resource file and it works fine:-

public class App {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader =
            new BufferedReader(
                new FileReader(
                    Objects.requireNonNull(
                        Objects.requireNonNull(
                            App.class.getClassLoader().getResource("file.txt")
                        ).getFile()
                    )
                )
            );
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
    }
}

I want to make a executable jar file with the resource file. I follow this. Unfortunately when I run the jar it can't find. Error:- ReadFileExample.jar!/file.txt (No such file or directory). Actually, I don't need to use IDE if it is easier to do it from the terminal or maven plugins, please let me know how can I add my resource file in the jar either by the IDE or by terminal or any maven plugin ?

Janez Kuhar
  • 3,705
  • 4
  • 22
  • 45
Masi Boo
  • 635
  • 1
  • 10
  • 24
  • Hi Masi. The link, which you've pasted, is meant for Maven projects. There are multiple ways executable jar: https://www.baeldung.com/executable-jar-with-maven – greenmarker Apr 18 '21 at 13:46
  • Does this answer your question? [How to read a file from a jar file?](https://stackoverflow.com/questions/2271926/how-to-read-a-file-from-a-jar-file) – Janez Kuhar Apr 18 '21 at 14:19

1 Answers1

1

new FileReader(

This bit means it will never work. FileReader reads files. And only files. Hence the name. You 'luck' into it working during dev, as the resource is an actual file at that point.

There's good news though. Your code is incredibly complicated and can be made much simpler:

  1. .getClassLoader().getResource(...) is more code AND worse than just .getResource. getCL can return null in exotic cases. Make sure to adjust the parameter; it is now relative to the place your class is in, and you can get back to 'go from root' by putting a slash in front.
  2. Don't use FileREader, obviously. Actually, never use that class.
  3. Your code fails to specify encoding. This is bad; the encoding will thus default to whatever the system you run it on has as default encoding which therefore by definition is not guaranteed to match what you stuck in that jar file. Always be explicit.
  4. These are 25 year old APIs, java has nicer ones these days. Let's use them to try to make this code easier to read.
  5. The requireNonNull calls are useless here; you already get an NPE if you try to pass a null ref to e.g. FileReader's constructor.
  6. Your code opens a resource and doesn't safely close it. This causes you to leak handles, which means your app will soon be 'dead' - it has a bunch of objects still in memory that are holding open OS-level file handles and the OS simply won't give any further handles to your process. Any attempt to do anything that interacts with the OS (make network connections, open files, etcetera) will just flat out not work anymore, until you shut down the VM and start it up again. That's why try-with-resources exists, to protect from this. This problem is hard to catch with trivial apps and tests.

Putting it all together:

try (var raw = App.class.getResourceAsStream("/file.txt");
  var in = new BufferedReader(new InputStreamReader(raw, StandardCharsets.UTF_8))) {
    String line = "";
    while ((line = in.readLine()) != null) {
        // process line here.
    }
}
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Thanks for details explanation. But the question was how to make an executable jar with the a resource file. My buggy code was working in the IDE. But I was not able to run the jar file. You didn't mention anything about how to do it? – Masi Boo Apr 18 '21 at 17:14
  • @MassiBoo Well, the example in this answer should get you well on your way. Then you just need to add something like `maven-jar-plugin` or `maven-assembly-plugin` to your `pom.xml`. Be sure you follow the [Standard Directory Layout](https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)! – Janez Kuhar Apr 18 '21 at 18:06
  • @MasiBoo your code was _never_ going to be able to read entries-in-a-jar file. Assuming you did the usual stuff (put the resources in src/main/resources), the 'hey they should show up in the jar file' part is automatic, that part is easy. The error you get can be caused EITHER by 'the jar file does not contain this resource' or, more likely, 'the code you wrote will fail with that exact error whether it is in there or not, because you cannot read resources in jar files with it'. – rzwitserloot Apr 19 '21 at 01:08
  • @rzwitserloot thnanks for your answer and helpful comments. I wonder shouldn't I need to close the in.close() after the while loop. – Masi Boo Apr 19 '21 at 07:15
  • @MasiBoo not needed - that `try(expr) {}` construct closes it for you, and closes it regardless of how you 'exit' the associated {}. Be it with return, running through it, breaking it, or exceptions. – rzwitserloot Apr 19 '21 at 11:13