Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java read file within static method, using ClassLoader gives FileNotFoundException

I want to read a file in my java class. My question is similar to this one, but there are two differences. first, I use a different project layout:

/src/com/company/project
/resources

In the resources folder I have a file called "test.txt":

/resources/test.txt

In the project folder I have a class test.java

/src/com/company/project/test.java

I want mu java class to be able to read the contents of test.txt in a STATIC METHOD. I've tried the following:

private static String parseFile()
{
    try
    {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        String fileURL = classLoader.getResource("test.txt").getFile();

        File file = new File(fileURL);


        ...
    }   
}

and the following paths:

File file1 = new File("test.txt");
File file2 = new File("/test.txt");
File file3 = new File("/resources/test.txt");

But they all throw a FileNotFoundException when I want to read the file. How can I correctly declare the path to my file in the snippet above with respect to my project setup and the fact that the method needs to be static?

like image 251
user1884155 Avatar asked Sep 02 '26 16:09

user1884155


2 Answers

You should use the class loader of the class which is in the same JAR as the resource instead of the TCCL. And then you need to specify the name of the resource with a full path. And it is typically not good to access those as files. Just open it directly for read (or copy it to a temp file if you need to):

InputStream is =
  Project.class.getClassLoader().getResourceAsStream("/resource/test.txt");

BTW: if you simply want to open a file, you need to use a relative file name. This is searched relative to the start dir, which is normally the project main dir (in eclipse):

File resource = new File("resource/test.txt");

(but this wont work if you package it up as a JAR).

like image 147
eckes Avatar answered Sep 05 '26 04:09

eckes


After endless trials, I gave up on ClassLoader and getResource methods of any kind. Absolutely nothing worked, especially if the opening attempt was made from another project. I always ended up getting the bin folder instead of the src folder. So I devised the following work around:

public class IOAccessory {

    public static String getProjectDir() {
        try {
            Class<?> callingClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
            URL url = callingClass.getProtectionDomain().getCodeSource().getLocation();
            URI parentDir = url.toURI().resolve("..");          
            return parentDir.getPath();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return "";
    }
}

The getProjectDir method returns the physical path of the project from which it was called, e.g. C:/workspace/MyProject/. After that, all you need to do is concatenate the relative path in MyProject of your resource file to open the stream:

public void openResource() throws IOException {
    InputStream stream = null;
    String projectDir = IOAccessory.getProjectDir();
    String filePath = "resources/test.txt";
    try {
        stream = new FileInputStream(projectDir + filePath);
        open(stream);
    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        if (stream != null)
            stream.close();
    }
}

This technique works whether the openResource method is static or non-static, and whether it is called from within the project or from another project on the build path.

like image 30
lu salmata Avatar answered Sep 05 '26 04:09

lu salmata