java - resource - spring read file from classpath




How to really read text file from classpath in Java (11)

Scenario:

1) client-service-1.0-SNAPSHOT.jar has dependency read-classpath-resource-1.0-SNAPSHOT.jar

2) we want to read content of class path resources (sample.txt) of read-classpath-resource-1.0-SNAPSHOT.jar through client-service-1.0-SNAPSHOT.jar.

3) read-classpath-resource-1.0-SNAPSHOT.jar has src/main/resources/sample.txt

Here is working sample code I prepared, after 2-3days wasting my development time, I found the complete end-to-end solution, hope this helps to save your time

1.pom.xml of read-classpath-resource-1.0-SNAPSHOT.jar

<?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
            <groupId>jar-classpath-resource</groupId>
            <artifactId>read-classpath-resource</artifactId>
            <version>1.0-SNAPSHOT</version>
            <name>classpath-test</name>
            <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <org.springframework.version>4.3.3.RELEASE</org.springframework.version>
                <mvn.release.plugin>2.5.1</mvn.release.plugin>
                <output.path>${project.artifactId}</output.path>
                <io.dropwizard.version>1.0.3</io.dropwizard.version>
                <commons-io.verion>2.4</commons-io.verion>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                    <version>${org.springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                    <version>${org.springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>commons-io</groupId>
                    <artifactId>commons-io</artifactId>
                    <version>${commons-io.verion}</version>
                </dependency>
            </dependencies>
            <build>
                <resources>
                    <resource>
                        <directory>src/main/resources</directory>
                    </resource>
                </resources>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-release-plugin</artifactId>
                        <version>${mvn.release.plugin}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.1</version>
                        <configuration>
                            <source>1.8</source>
                            <target>1.8</target>
                            <encoding>UTF-8</encoding>
                        </configuration>
                    </plugin>
                    <plugin>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>2.5</version>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <archive>
                                <manifest>
                                    <addClasspath>true</addClasspath>
                                    <useUniqueVersions>false</useUniqueVersions>
                                    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                    <mainClass>demo.read.classpath.resources.ClassPathResourceReadTest</mainClass>
                                </manifest>
                                <manifestEntries>
                                    <Implementation-Artifact-Id>${project.artifactId}</Implementation-Artifact-Id>
                                    <Class-Path>sample.txt</Class-Path>
                                </manifestEntries>
                            </archive>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-shade-plugin</artifactId>
                        <version>2.2</version>
                        <configuration>
                            <createDependencyReducedPom>false</createDependencyReducedPom>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                        </configuration>
                        <executions>
                            <execution>
                                <phase>package</phase>
                                <goals>
                                    <goal>shade</goal>
                                </goals>
                                <configuration>
                                    <transformers>
                                        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                            <mainClass>demo.read.classpath.resources.ClassPathResourceReadTest</mainClass>
                                        </transformer>
                                    </transformers>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </project>

2.ClassPathResourceReadTest.java class in read-classpath-resource-1.0-SNAPSHOT.jar that loads the class path resources file content.

package demo.read.classpath.resources;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public final class ClassPathResourceReadTest {
    public ClassPathResourceReadTest() throws IOException {
        InputStream inputStream = getClass().getResourceAsStream("/sample.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        List<Object> list = new ArrayList<>();
        String line;
        while ((line = reader.readLine()) != null) {
            list.add(line);
        }
        for (Object s1: list) {
            System.out.println("@@@ " +s1);
        }
        System.out.println("getClass().getResourceAsStream('/sample.txt') lines: "+list.size());
    }
}

3.pom.xml of client-service-1.0-SNAPSHOT.jar

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>client-service</groupId>
    <artifactId>client-service</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>jar-classpath-resource</groupId>
            <artifactId>read-classpath-resource</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <useUniqueVersions>false</useUniqueVersions>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            <mainClass>com.crazy.issue.client.AccessClassPathResource</mainClass>
                        </manifest>
                        <manifestEntries>
                            <Implementation-Artifact-Id>${project.artifactId}</Implementation-Artifact-Id>
                            <Implementation-Source-SHA>${buildNumber}</Implementation-Source-SHA>
                            <Class-Path>sample.txt</Class-Path>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                    <filters>
                        <filter>
                            <artifact>*:*</artifact>
                            <excludes>
                                <exclude>META-INF/*.SF</exclude>
                                <exclude>META-INF/*.DSA</exclude>
                                <exclude>META-INF/*.RSA</exclude>
                            </excludes>
                        </filter>
                    </filters>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.crazy.issue.client.AccessClassPathResource</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

4.AccessClassPathResource.java instantiate ClassPathResourceReadTest.java class where, it is going to load sample.txt and prints its content also.

package com.crazy.issue.client;

import demo.read.classpath.resources.ClassPathResourceReadTest;
import java.io.IOException;

public class AccessClassPathResource {
    public static void main(String[] args) throws IOException {
        ClassPathResourceReadTest test = new ClassPathResourceReadTest();
    }
}

5.Run Executable jar as follows:

[[email protected] lib]$ java -jar client-service-1.0-SNAPSHOT.jar
****************************************
I am in resources directory of read-classpath-resource-1.0-SNAPSHOT.jar
****************************************
3) getClass().getResourceAsStream('/sample.txt'): 3

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.


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

this.getClass().getResourceAsStream("/SomeTextFile.txt");

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();

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.


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


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);
}

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");

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


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

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.


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();
                    }
                }
            }
        }

    }

}




classpath