2

We're developing a webapp and we have some files to read from a resources directory. During preliminary development and testing, we'd like to be able to read directly from the file in the resources directory. On the other hand, we want to read the resource file from a jar file when the webapp is deployed.

I've read other questions that indicate how to read files from jars. The essence of the idea is to get a BufferedReader and to read from that.

I've written the following code that allows me to create a BufferedReader from either the file system or a jar file, passing in the file name, e.g. myResource.txt, and the ClassLoader, e.g. getClass().getClassLoader(). It seems like it could be made better and/or simpler. Please help.

 public static BufferedReader getBufferedReader(String fileToFind,
                                               ClassLoader classLoader) {
    BufferedReader bufferedReader = null;
    // Try to find file in file system
    final URL resource =
            classLoader.getResource(fileToFind);
    if (resource != null) {
        String fileName = resource.getFile();
        if (fileName != null) {
            try {
                final FileReader fileReader = new FileReader(fileName);
                bufferedReader = new BufferedReader(fileReader);
            }
            catch (FileNotFoundException e) {} // no problem, move on
        }
    }
    if (bufferedReader == null) {
        // Try to find file in jar file
        InputStream inputStream =
                classLoader.getResourceAsStream(fileToFind);
        final InputStreamReader streamReader = new InputStreamReader(inputStream);
        bufferedReader = new BufferedReader(streamReader);
    }
    return bufferedReader;
}
kc2001
  • 5,008
  • 4
  • 51
  • 92

2 Answers2

4

Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:

InputStream in = getClass().getResourceAsStream("/file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.

Vinit Mehta
  • 449
  • 4
  • 13
2

One cannot turn a resource "file" inside a jar into a File. Only when classpath is immediately on classes, such as an unpacked war file. Such a resource has an URL like file:jar:/.../xxx.jar!.../yyy.txt

However, one could use Path & a file system view to copy a Path from a resource.

In your code it suffices to just use getResourceAsStream.

public static BufferedReader getBufferedReader(String fileToFind,
                                               ClassLoader classLoader) {
    InputStream inputStream = classLoader.getResourceAsStream(fileToFind);
    InputStreamReader streamReader = new InputStreamReader(inputStream,
        StandardCharsets.UTF_8);
    return new BufferedReader(streamReader);
}

Mind fileToFind should not start with a / and should be an absolute path, when using a ClassLoader.

I specified the Charset, as you are taking the default, which would differ on a Linux production server, and a local Windows developer's machine.

kc2001
  • 5,008
  • 4
  • 51
  • 92
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138