4

I packaged my Spring Boot project into a JAR using maven. I want to read the names of all directories under "static/foo" in the resources folder.

Tried the following using the Apache Commons library:

String fooPath = "static/foo/";
List<String> fooFolders = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream(fooPath), Charsets.UTF_8);
// The fooFolders list is empty ...

UPDATE

This solution worked (slightly modified from https://stackoverflow.com/a/48190582/1427624) using JarFile:

String fooPath = "static/foo";
URL url = Thread.currentThread().getContextClassLoader().getResource(fooPath);

// Not running from JAR
if (url.getProtocol().equals("file"))
{
    try {
        // Get list of subdirectories' folder names
        List<String> fooFolders = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream(fooPath), Charsets.UTF_8);

        // Loop subdirectories
        for (String fooFolder : fooFolders) {
            // The current subdirectory path
            String fooFolderPath = fooPath + "/" + fooFolder;

            // Loop all files in this subdirectory, if needed
            List<String> fooFiles = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream(fooFolderPath), Charsets.UTF_8);

            for (String fooFile : fooFiles) {
                // The updated path of the file
                String fooFilePath = fooFolderPath + "/" + fooFile;

                // Read the file's content
                InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fooFilePath);
                StringWriter writer = new StringWriter();
                IOUtils.copy(inputStream, writer, Charsets.UTF_8);
                String fileContent = writer.toString();
            }
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

// Running from JAR
else if (url.getProtocol().equals("jar")) {
    String dirname = fooPath + "/";
    String path = url.getPath();
    String jarPath = path.substring(5, path.indexOf("!"));

    List<String> fooFolders = new ArrayList<String>();
    HashMap<String, List<String>> fooFiles = new HashMap<String, List<String>>();

    try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String jarEntryName = entry.getName();

            String updated_dir_name = "BOOT-INF/classes/" + dirname;

            // Only get files that are in the directory we require (fooPath)
            if (jarEntryName.startsWith(updated_dir_name) && !dirname.equals(updated_dir_name)) {

                // Get the resource URL
                URL resourceURL = Thread.currentThread().getContextClassLoader().getResource(jarEntryName);

                // Files only
                if (!jarEntryName.endsWith("/")) {

                    // Split the foo number and the file name
                    String[] split = jarEntryName.split("/");

                    // First level subdirectories inside fooPath
                    // BOOT-INF/classes/static/foo/1/myfile.html
                    // We want to read the folder name "1"
                    String folderName = split[split.length - 2];

                    // If you want to read this file
                    // Read the file's content
                    // InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceURL);
                }
            }
        }
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
P-S
  • 3,876
  • 1
  • 29
  • 26

3 Answers3

1

Sounds like this could be solved by https://stackoverflow.com/a/3923685/7610371

The "core" bits from the answer above:

InputStream resourceStream = this.getClass().getClassLoader().getResourceAsStream(fooPath);
BufferedReader br = new BufferedReader(new InputStreamReader(resourceStream)) 
String resource;

while ((resource = br.readLine()) != null) {
    // ... resource is the next filename; you can add it to an array
    // or use it here
}
xenocratus
  • 116
  • 4
  • This does not raise a nullpointerexception error so I assume the path is correct, but resourceStream.available() returns 0 (it's not entering the while loop)... If I change the path to a wrong one, I get a null error, so why is the stream empty ... – P-S Feb 26 '19 at 15:57
  • Can you debug the application? You could try and follow the code through the getResource calls. Also, you could check the order used by getResource in ClassLoader.java for searching for the resource, it might be that it finds something with the same name in a different place – xenocratus Feb 26 '19 at 16:08
  • I mean when debugging in Eclipse, your code works, I can iterate the names of the subdirectories - br.breakline() returns the folders' names. However, when I java -jar the project, br.readLine() returns null ... That's with using the same fooPath value (also tried the absolute path which is /BOOT-INF/classes/static/foo)... – P-S Feb 26 '19 at 16:32
  • I'm not sure if this would work better for you: https://smarterco.de/java-load-file-from-classpath-in-spring-boot/ – xenocratus Feb 26 '19 at 17:12
  • This works when I run in Eclipse, but not when I package everything in a jar using maven and run the jar itself... – P-S Feb 27 '19 at 12:42
  • Yes, a whole bunch of variations of the path ... static/foo, /static/foo, /static/foo/, /BOOT-INF/classes/static/foo/, /BOOT-INF/classes/static/foo, BOOT-INF/classes/static/foo, BOOT-INF/classes/static/foo/ ... It works when running from Eclipse as an application, but when I mvn package and java -jar, it stops working, even though I don't get nullpointer on the path, but the inputstream is just not reading anything – P-S Feb 27 '19 at 13:06
  • Got it to work using filtering the all entries in the JAR file. Updated my question with the solution. – P-S Feb 27 '19 at 14:17
0

I think you should use FileUtils instead.

In particular, the method listFilesAndDirs with the filter DirectoryFileFilter.

Mickael
  • 4,458
  • 2
  • 28
  • 40
  • File dir = new File(fooPath); List files = (List) FileUtils.listFilesAndDirs(dir, DirectoryFileFilter.INSTANCE, DirectoryFileFilter.INSTANCE); .... Same problem with @funkyjelly, it's not reading my path as a directory – P-S Feb 26 '19 at 15:59
0

You can also simply do the below :

 File f = new File("static/foo/");
 File[] arr = f.listFiles();
 for (File file : arr) {
     if (file.isDirectory())
        System.out.println(file);
 }
nullPointer
  • 4,419
  • 1
  • 15
  • 27