413

I am trying to read a text file which is set in CLASSPATH system variable. Not a user variable.

I am trying to get input stream to the file as below:

Place the directory of file (D:\myDir) in CLASSPATH and try below:

InputStream in = this.getClass().getClassLoader().getResourceAsStream("SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("/SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("//SomeTextFile.txt");

Place full path of file (D:\myDir\SomeTextFile.txt) in CLASSPATH and try the same above 3 lines of code.

But unfortunately NONE of them are working and I am always getting null into my InputStream in.

Mahozad
  • 18,032
  • 13
  • 118
  • 133
Chaitanya MSV
  • 6,706
  • 12
  • 40
  • 46

17 Answers17

668

With the directory on the classpath, from a class loaded by the same classloader, you should be able to use either of:

// From ClassLoader, all paths are "absolute" already - there's no context
// from which they could be relative. Therefore you don't need a leading slash.
InputStream in = this.getClass().getClassLoader()
                                .getResourceAsStream("SomeTextFile.txt");
// From Class, the path is relative to the package of the class unless
// you include a leading slash, so if you don't want to use the current
// package, include a slash like this:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");

If those aren't working, that suggests something else is wrong.

So for example, take this code:

package dummy;

import java.io.*;

public class Test
{
    public static void main(String[] args)
    {
        InputStream stream = Test.class.getResourceAsStream("/SomeTextFile.txt");
        System.out.println(stream != null);
        stream = Test.class.getClassLoader().getResourceAsStream("SomeTextFile.txt");
        System.out.println(stream != null);
    }
}

And this directory structure:

code
    dummy
          Test.class
txt
    SomeTextFile.txt

And then (using the Unix path separator as I'm on a Linux box):

java -classpath code:txt dummy.Test

Results:

true
true
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    You mixed relative and absolute paths up. A path that starts with "/" is absolute (i.e. starts from whatever is listed in CLASSPATH). All other paths are relative to the package of the class on which you call `getResourceAsStream()` – Aaron Digulla Sep 23 '09 at 07:25
  • I've fixed your examples and added another one to show how a relative path works. – Aaron Digulla Sep 23 '09 at 07:38
  • 22
    No, you *broke* my example. I'll edit the comments to make them clearer, but the point is that using ClassLoader all paths are assumed to be absolute already. There's nothing for them to be relative to. – Jon Skeet Sep 23 '09 at 07:57
  • Thanks Jon! I spent a while looking for this, also. The only other piece of information I needed was that DocumentBuilder parse method takes "File" and "InputStream" objects both. – john_science Jul 04 '12 at 03:40
  • More than 3 years, and this is still the most useful post about the topic!!! Thanks Jon!! – mdm Dec 14 '12 at 10:52
  • 7
    Also do not use Java.IO.File.Separator. It wont work on windows. If you are running this code on windows it still has to be '/' and not '\' – Pradhan Jun 14 '13 at 17:56
  • 36
    @Pradhan: No, you shouldn't be using `File.Separator` - because you're not asking for a *file*, you're asking for a *resource*. It's important to understand that the abstraction involved isn't the file system. – Jon Skeet Jun 14 '13 at 17:59
  • also the thread context classloader? http://stackoverflow.com/questions/1771679/difference-between-threads-context-class-loader-and-normal-classloader – Kalpesh Soni Aug 26 '13 at 15:09
  • 1
    @jagdpanzer: Well it's only for classes which are loaded by the same classloader, basically - and it's because `Class.getResourceAsStream` is really a convenience method for calling `ClassLoader.getResourceAsStream`, but with the additional feature of "relative" resources. If you're specifying an absolute resource, then any call using the same classloader will do the same thing. – Jon Skeet Nov 05 '15 at 18:07
  • @qwebek: "Didn't work" doesn't really tell us anything about *exactly* what you tried or what went wrong. This answer definitely *does* work, but you do need to follow the instructions precisely. – Jon Skeet Mar 04 '16 at 18:31
  • Can you please add to your post an exception safe code? – Stephan Apr 21 '16 at 15:35
  • @Stephan: That warning isn't really needed for this code - I don't think it would ever throw. – Jon Skeet Apr 21 '16 at 15:37
  • The main difference is that when using the getResourceAsStream on a ClassLoader instance, the path is treated as absolute starting from the root of the classpath. When used against a Class instance, the path could be relative to the package, or an absolute path, which is hinted by the leading slash. – mkebri Oct 19 '18 at 08:41
  • Hi Jon, could you elaborate a bit on `from a class loaded by the same classloader`? Does that refer to whichever class that called `getResourceAsStream`? Thanks – Weishi Z Nov 29 '18 at 05:39
  • @WeishiZeng: Not necessarily. I mean "the same classloader that is used to load classes from the classpath, or wherever you're trying to load resources from" - it's hard to be more precise than that, as the context can vary so much. – Jon Skeet Nov 29 '18 at 06:22
  • How is "SomeTextFile.txt" an absolute path? – Philip Rego Feb 13 '19 at 14:01
  • @PhilipRego: It's absolute in that when passed to a classloader, it's unambiguous. The classloader effectively provides the context. It's "relative to the root of the resources served by the classloader" if you want to think of it like that. – Jon Skeet Feb 13 '19 at 14:30
132

When using the Spring Framework (either as a collection of utilities or container - you do not need to use the latter functionality) you can easily use the Resource abstraction.

Resource resource = new ClassPathResource("com/example/Foo.class");

Through the Resource interface you can access the resource as InputStream, URL, URI or File. Changing the resource type to e.g. a file system resource is a simple matter of changing the instance.

yawn
  • 8,014
  • 7
  • 29
  • 34
  • 8
    Could you please provide a sample code on how this can be used in file I/O? I can't find a _decent_, _explicit_ and _straightforward_ way on how to use it in the Internet :(((( –  Feb 11 '14 at 16:00
  • 1
    Works like a charm. The provided one liner is all you need. Use the stream parsing from other examples if you don't know how to get a string from the stream. – Joseph Lust Feb 16 '14 at 18:14
  • I had a bit of trouble figuring out exactly what to do with the resource variable as well. I've edited the answer with a bit more detail – DavidZemon Dec 02 '14 at 14:10
  • I was already using Spring and trying the "pure java" way. It was killing me, the differences between getResource, getResourceAsStream, etc, with no good working examples. This is a perfect example of encapsulation, so I don't have to care. – TinkerTenorSoftwareGuy Jan 19 '17 at 16:08
  • 3
    Be careful, if you package your project into a jar you should use an InputStream. If you use a File it work in your IDE but will fail if you test it from the jar. If you really need a File try with https://stackoverflow.com/questions/4317035/how-to-convert-inputstream-to-virtual-file – Rafael Membrives Aug 30 '17 at 07:40
  • `String data = StreamUtils.copyToString(new ClassPathResource("data.txt").getInputStream(), Charset.defaultCharset());` – conspicillatus May 06 '21 at 14:08
72

This is how I read all lines of a text file on my classpath, using Java 7 NIO:

...
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;

...

Files.readAllLines(
    Paths.get(this.getClass().getResource("res.txt").toURI()), Charset.defaultCharset());

NB this is an example of how it can be done. You'll have to make improvements as necessary. This example will only work if the file is actually present on your classpath, otherwise a NullPointerException will be thrown when getResource() returns null and .toURI() is invoked on it.

Also, since Java 7, one convenient way of specifying character sets is to use the constants defined in java.nio.charset.StandardCharsets (these are, according to their javadocs, "guaranteed to be available on every implementation of the Java platform.").

Hence, if you know the encoding of the file to be UTF-8, then specify explicitly the charset StandardCharsets.UTF_8

Peter Perháč
  • 20,434
  • 21
  • 120
  • 152
  • 1
    Thank you for the NIO solution - so few people use this great API it is a shame. – mvreijn Apr 14 '15 at 18:50
  • 7
    To read into a single String try. new String(Files.readAllBytes(Paths.get(MyClass.class.getResource(resource).toURI()))); – Theo Briscoe Jul 23 '16 at 12:03
  • 2
    Best solution for me, as it doesn't need any dependencies, like Spring or Commons IO. – Bernie Sep 25 '16 at 09:44
  • 4
    This will fail if your resource file is inside a jar, e.g. a maven module. In that case you'll need to use something like `Spring`'s `StreamUtils.copyToString`. – Somu Feb 14 '20 at 09:33
27

Please try

InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");

Your tries didn't work because only the class loader for your classes is able to load from the classpath. You used the class loader for the java system itself.

tangens
  • 39,095
  • 19
  • 120
  • 139
  • Not sure about the "/" though. A relative path might work better in this case. – VonC Sep 23 '09 at 06:53
  • 3
    If you use it without "/" you are looking for your file inside the package of "this". – tangens Sep 23 '09 at 07:04
  • 1
    InputStream file = this.getClass().getResourceAsStream("SomeTextFile.txt"); InputStream file = this.getClass().getResourceAsStream("/SomeTextFile.txt"); InputStream file = this.getClass().getResourceAsStream("//SomeTextFile.txt"); None of the above worked :( – Chaitanya MSV Sep 23 '09 at 07:37
  • 1
    @Chaitanya: Can you run the example from John Skeet's answer? – Aaron Digulla Sep 23 '09 at 07:40
  • Here are a few [good examples for getResourceAsStream](https://www.codota.com/code/java/methods/java.lang.ClassLoader/getResourceAsStream) – drorw Nov 17 '18 at 22:13
21

To actually read the contents of the file, I like using Commons IO + Spring Core. Assuming Java 8:

try (InputStream stream = new ClassPathResource("package/resource").getInputStream()) {
    IOUtils.toString(stream);
}

Alternatively:

InputStream stream = null;
try {
    stream = new ClassPathResource("/log4j.xml").getInputStream();
    IOUtils.toString(stream);
} finally {
    IOUtils.closeQuietly(stream);
}
qtopierw
  • 1,447
  • 14
  • 23
Pavel
  • 3,481
  • 26
  • 31
  • What about closing the inputstream? – Stephan Apr 21 '16 at 15:32
  • 1
    The stream will be closed automatically. It is a feature of Java 7 "Try with resources" https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html – Michał Maciej Gałuszka Sep 13 '18 at 06:58
  • 2
    Only if it is inside the try statement, which is not the case here. It should have been try (final InputStream stream = new ClassPathResource("/log4j.xml").getInputStream()) {... – andresp May 13 '19 at 13:23
17

Somehow the best answer doesn't work for me. I need to use a slightly different code instead.

ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");

I hope this help those who encounters the same issue.

user1695166
  • 621
  • 7
  • 9
  • This helped me on Android as well where a class was loaded by the application loader, but a key that it needed was lazy loaded in the UI thread. – asokan Jul 04 '16 at 22:35
  • You need to provide information on why the best answer does not work for you (e.g. your application's structure, the framework you are using, the error etc.). The best answer said clearly that 1) the directory needs to be on classpath, 2) you need to request from a class loaded by the same class loader. Chances are one of these assumptions does not hold for your application. Also the context class loader is very discouraged as it was introduced as a hack. Some framework does make use of it but it is important to know the implication (which requires you describe your project's background) – Xinchao Jul 20 '18 at 06:43
  • This works in a static context (unlike other solutions mentioned here). – Vitaly Sazanovich Jun 21 '21 at 20:17
16

To get the class absolute path try this:

String url = this.getClass().getResource("").getPath();
5agado
  • 2,444
  • 2
  • 21
  • 30
webcom
  • 169
  • 1
  • 2
8

If you use Guava:

import com.google.common.io.Resources;

we can get URL from CLASSPATH:

URL resource = Resources.getResource("test.txt");
String file = resource.getFile();   // get file path 

or InputStream:

InputStream is = Resources.getResource("test.txt").openStream();

Ways to convert an InputStream to a String

Alexey Simonov
  • 414
  • 4
  • 12
  • The file path isn't any use if the resource is in a JAR or WAR file. – user207421 Aug 07 '17 at 06:33
  • The getFile method of URL does not return a file name. It just returns the path portion of the URL, which is not guaranteed to be a valid file name. (The URL class was part of Java 1.0; back then, most URLs did in fact refer to physical files on either the same computer or a different computer.) – VGR Sep 21 '18 at 19:34
  • I needed to retrieve images I had stored in a submap under ```recources```. Worked locally with my relative filePath, but the ```Resources.getResource("submap/file").openStream()``` was the ONLY solution I got working when deployed on a remote server – Paul Feb 17 '21 at 14:08
3

To read the contents of a file into a String from the classpath, you can use this:

private String resourceToString(String filePath) throws IOException, URISyntaxException
{
    try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
    {
        return IOUtils.toString(inputStream);
    }
}

Note:
IOUtils is part of Commons IO.

Call it like this:

String fileContents = resourceToString("ImOnTheClasspath.txt");
BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
1

You say "I am trying to read a text file which is set in CLASSPATH system variable." My guess this is on Windows and you are using this ugly dialog to edit the "System Variables".

Now you run your Java program in the console. And that doesn't work: The console gets a copy of the values of the system variables once when it is started. This means any change in the dialog afterwards doesn't have any effect.

There are these solutions:

  1. Start a new console after every change

  2. Use set CLASSPATH=... in the console to set the copy of the variable in the console and when your code works, paste the last value into the variable dialog.

  3. Put the call to Java into .BAT file and double click it. This will create a new console every time (thus copying the current value of the system variable).

BEWARE: If you also have a User variable CLASSPATH then it will shadow your system variable. That is why it is usually better to put the call to your Java program into a .BAT file and set the classpath in there (using set CLASSPATH=) rather than relying on a global system or user variable.

This also makes sure that you can have more than one Java program working on your computer because they are bound to have different classpaths.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
1

My answer is not exactly what is asked in the question. Rather I am giving a solution exactly how easily we can read a file into out java application from our project class path.

For example suppose a config file name example.xml is located in a path like below:-

com.myproject.config.dev

and our java executable class file is in the below path:-

com.myproject.server.main

now just check in both the above path which is the nearest common directory/folder from where you can access both dev and main directory/folder (com.myproject.server.main - where our application’s java executable class is existed) – We can see that it is myproject folder/directory which is the nearest common directory/folder from where we can access our example.xml file. Therefore from a java executable class resides in folder/directory main we have to go back two steps like ../../ to access myproject. Now following this, see how we can read the file:-

package com.myproject.server.main;

class Example {

  File xmlFile;

  public Example(){
       String filePath = this.getClass().getResource("../../config/dev/example.xml").getPath();
       this.xmlFile = new File(filePath);
    }

  public File getXMLFile() {
      return this.xmlFile;
  }
   public static void main(String args[]){
      Example ex = new Example();
      File xmlFile = ex.getXMLFile();
   }
}
Abhijit Pritam Dutta
  • 5,521
  • 2
  • 11
  • 17
1

If you compile your project in jar file: you can put your file in resources/files/your_file.text or pdf;

and use this code:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;

public class readFileService(){
    private static final Logger LOGGER = LoggerFactory.getLogger(readFileService.class);


    public byte[] getFile(){
        String filePath="/files/your_file";
        InputStream inputStreamFile;
        byte[] bytes;
        try{
            inputStreamFile = this.getClass().getResourceAsStream(filePath);
            bytes = new byte[inputStreamFile.available()];
            inputStreamFile.read(bytes);    
        } catch(NullPointerException | IOException e) {
            LOGGER.error("Erreur read file "+filePath+" error message :" +e.getMessage());
            return null;
        }
        return bytes;
    } 
}
Boendal
  • 2,496
  • 1
  • 23
  • 36
Ahmed ALI
  • 41
  • 4
-1

I am using webshpere application server and my Web Module is build on Spring MVC. The Test.properties were located in the resources folder, i tried to load this files using the following:

  1. this.getClass().getClassLoader().getResourceAsStream("Test.properties");
  2. this.getClass().getResourceAsStream("/Test.properties");

None of the above code loaded the file.

But with the help of below code the property file was loaded successfully:

Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");

Thanks to the user "user1695166".

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
  • 1
    Welcome to Stack Overflow! Please don't add "thanks" as answers even if you're also partially providing how your solution went, if your solutions is the same as another post it doesn't need to be added. After you've invested some time in the site you'll gain sufficient [privileges](//stackoverflow.com/privileges) to upvote answers you like, which is the Stack Overflow way of saying thank you. – SuperBiasedMan Aug 10 '15 at 13:26
-1

Use org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));

Charu Khurana
  • 4,511
  • 8
  • 47
  • 81
-2

Don't use getClassLoader() method and use the "/" before the file name. "/" is very important

this.getClass().getResourceAsStream("/SomeTextFile.txt");
sachinthana87
  • 39
  • 1
  • 6
-4
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class ReadFile

{
    /**
     * * feel free to make any modification I have have been here so I feel you
     * * * @param args * @throws InterruptedException
     */

    public static void main(String[] args) throws InterruptedException {
        // thread pool of 10
        File dir = new File(".");
        // read file from same directory as source //
        if (dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {
                // if you wanna read file name with txt files
                if (file.getName().contains("txt")) {
                    System.out.println(file.getName());
                }

                // if you want to open text file and read each line then
                if (file.getName().contains("txt")) {
                    try {
                        // FileReader reads text files in the default encoding.
                        FileReader fileReader = new FileReader(
                                file.getAbsolutePath());
                        // Always wrap FileReader in BufferedReader.
                        BufferedReader bufferedReader = new BufferedReader(
                                fileReader);
                        String line;
                        // get file details and get info you need.
                        while ((line = bufferedReader.readLine()) != null) {
                            System.out.println(line);
                            // here you can say...
                            // System.out.println(line.substring(0, 10)); this
                            // prints from 0 to 10 indext
                        }
                    } catch (FileNotFoundException ex) {
                        System.out.println("Unable to open file '"
                                + file.getName() + "'");
                    } catch (IOException ex) {
                        System.out.println("Error reading file '"
                                + file.getName() + "'");
                        // Or we could just do this:
                        ex.printStackTrace();
                    }
                }
            }
        }

    }

}
Janny
  • 681
  • 1
  • 8
  • 33
Helper
  • 1
-6

you have to put your 'system variable' on the java classpath.

Salandur
  • 6,409
  • 2
  • 22
  • 23