简体   繁体   中英

Why to use java.lang.ClassLoader.getResource for resource within jar

Using Java 8, Tomcat 8+.

I have faced with such problem - I'm trying to read txt resource within jar in lib. I have used the following code:

import java.io.File;
import org.apache.commons.io.FileUtils;

// ....    
// code within some class method
File file = new File(superService.getClass().getClassLoader()
                    .getResource("com/domain/example/sorry/confidential/little_text.txt")
                    .getFile())
return FileUtils.readFileToString(file, "UTF-8")

Though it worked well running from my Intellij IDEA, I got such kind of exception after deploy on Tomcat server:

java.io.FileNotFoundException: File 'file:/usr/local/tomcat/webapps/prod-lims/WEB-INF/lib/abc-1.2-SNAPSHOT.jar.com/domain/example/sorry/confidential/little_text.txt' does not exist

And after that I found a lot of answers in SO and other sites that I need to use ClassLoader.getResourceAsStream() or Class.getResourceAsStream() methods for resources within JAR. Of course, I tried to re-design my code in old-style way and - voila: - it works now:

import java.io.BufferedReader;
import java.io.InputStreamReader;

// ....    
// code within some class method
InputStream inputStream = superService.getClass().getClassLoader()
               .getResourceAsStream("com/domain/example/sorry/confidential/little_text.txt")


StringBuilder resultStringBuilder = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))
    try {
        String line;
        while ((line = br.readLine()) != null) {
            resultStringBuilder.append(line).append("\n");
        }
        } catch(Exception e) {
        //just a formal catch - don't mind for now
    }

return resultStringBuilder.toString()

Ok, I'm happy with the working solution. But I can not find any clear explanation anywhere: why getResourceAsStream works and at the same time 'File' approach doesn't work for resources within JAR? I'm curious because superService.getClass().getClassLoader().getResource("com/domain/example/sorry/confidential/little_text.txt") returns not null, but the constructed file has canRead() == false and isExist() == false .

File, FileInputStream, FileUtils et cetera are intended to access the file system, and a "file" that is embedded inside a JAR is not actually a file from the file system's point of view. Thus, you can only access those embedded files through tools that are actually intended to read from inside an archive (a JAR is just a fancy ZIP, basically).

Incidentally, the fact that your File object in Java is non-null does not mean the file actually exists. You could do this just fine:

File file = new File("I:\\do\\not.exist");

and file would be non-null (but isReadable() and isExist() should be false). Which is the same behaviour you get for your resource.

It likely works in the IDE because the file does actually exist as a non-archived file in your workspace.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM