xbwxlvn
xbwxlvn

Reputation: 39

Spring boot - list all the files in the classpath

In a spring boot application, I have application.yaml file with properties as

files:
  paths: /csvfiles/

While in src/main/resource, we have a folder named csvfiles which contains the list of csv files which I want to read.

I am trying to search the same, but didn't get any proper way to achieve the same.

getClass().getResourceAsStream("/files/paths") cal only be used to get the particular file but not the list of files.

After listing all the files, I want read them sequentially

Upvotes: 1

Views: 5345

Answers (4)

jeeva nantham
jeeva nantham

Reputation: 843

List<File> result = Files.walk(Paths.get("classpathname"))
.filter(Files::isRegularFile)
.map(Path::toFile)
.collect(Collectors.toList());

This result will gives you list of file and their content.

Upvotes: 0

rzwitserloot
rzwitserloot

Reputation: 103018

It's YourClass.class.getResourceAsStream, not getClass(), which has the potential to break if you subclass stuff.

the getResource mechanism fundamentally doesn't know what folders are and cannot give you a listing. Period. ClassLoaders are an abstraction, they can be implemented as reading jar files, directories on a disk, but also loading from a network, retrieving from a database, or generated on the fly, and crucially, there simply is no please list folder contents option, so whatever you find out there (and there's some libraries and such) are hacks that fail to work in such cases.

The common solution is to create a text file that lists the resources. Now you are no longer dependent on the unavailable 'list files' operation: Instead, you ask for all editions of that text file on any classpath entry, and then just read every file so listed. When applied to classes, this is called the SPI system (Service Provider Interface). Built into java.* itself is the ability to read them, though they are designed for classes, not files, so I'm not sure the SPI system directly applies here. The principle works fine, though.

If you want this to be automated, as part of your build you'd have to generate that file automatically. Not sure how you'd do that with spring boot, you may have to maintain it by hand.

An example:

class CsvResource {
  
  public CsvResource(String name) {
    try (var in = CsvResource.class.getResourceAsStream("/csvfiles/" + name)) {
      read(in); // you write this one.
    }
  }

  public static List<String> getAvailableNames() {
    try (var in = CsvResource.class.getResourceAsStream("/csvfiles/listing.txt")) {
      Arrays.stream(
        new String(in.readAllBytes, StandardCharsets.UTF_8).split("\s*\\n\s*"))
        .filter(x -> !x.isEmpty())
        .filter(x -> !x.startsWith("#"))
        .collect(Collectors.toList());
    }
  }
}

It would be fair to catch IOException, especially for missing csvfiles, and rewrap into a runtime exception - that file not being there at runtime is a developer or devops error, and those should be Errors or at least RuntimeExceptions.

Upvotes: 1

Abhijit Sarkar
Abhijit Sarkar

Reputation: 24578

Assuming your code is built into an executable jar, there’s no src/main/resources in the jar. What you can do is list the contents of the jar file, and then based on the path of each entry, select the ones with csvfiles in the path.

To find out which jar a class is from, see this. To list the contents of a jar file, see this.

Obviously, this won’t work when running locally, so you need an alternative. You can find the location of the class file with this and then navigate to the csvfiles directory relative to it.

Upvotes: 1

Senthil
Senthil

Reputation: 289

In Spring, One solution could be, you can inject the resources array from a folder which is part of classpath

@Value("classpath:path/*")
private Resource[] files;

Upvotes: 4

Related Questions