0

This method does not apply:

Files.walk(Paths.get("folder name"))

Because when the app is running, packaged as a jar, it does not contain File objects.

Is there a method for an app to walk through all the contents of one of its packages while it runs?

seinecle
  • 10,118
  • 14
  • 61
  • 120
  • See [How to list the files inside a JAR file?](https://stackoverflow.com/questions/1429172/how-to-list-the-files-inside-a-jar-file) –  Apr 14 '21 at 12:44
  • A jar file is just a zip file with a pre-defined structure. All standard libraries for zip files will work with jars – jr593 Apr 14 '21 at 13:35
  • Editors who closed this question as being a duplicate should look at my edits and the accepted answer to see that it is actually not one. – seinecle Apr 14 '21 at 16:30

2 Answers2

1

There is; open the jar file (using java.io.JarFile) and walk through the entries returned by entries(). There's also JarInputStream if your jar is being streamed in from elsewhere.

But, it sounds like you have equated 'jar file' with 'my application, at runtime'.

That's a tricky move. For starters, figuring out your own jar is possible but a little hacky, and more importantly, it then means your app straight up fails to work unless it is in jar form. This complicates deployment, development, and debugging.

There is no need to do it this way.

You can ask java for resources from 'whereever it is currently picking up class files'. A class file is a resource crucial to the running of your application. So is e.g. an icon file for a GUI app. Both should be coming from the same place, and where that is? That's abstracted away, and you should follow along with the abstraction, so that the 'load resource' code works just as well in debugging as it does at runtime.

The system for this is MyClass.class.getResource("file.txt") which will look for file.txt in the same place MyClass.class is located, even if it is in jar files, generated live, or obtained from a BLOB object in a database someplace, or streamed over a network.

The downside is, this system does not have an abstraction for listing files. Only for getting resources with a specific name.

The SPI system is the solution: Make a file that lists (one resource per line) the resources - instead of 'list dir', you 'parse each line of CONTENTS.txt' for the equivalent operation. You can then use annotation processors, if you must, to automatically create and maintain this content file.

ServiceLoader is baked into the JDK itself, but it's designed to load, specifically, class files and not other resources. But the principle is trivial and can be handwritten in about 5 lines of code.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Thank you! Indeed I meant at run time, in my own running app. For the SPI approach, have you any pointer for using annotation processors? I have never used them. – seinecle Apr 14 '21 at 13:56
  • 1
    @seinecle I wrote one myself ages ago I still use and never bothered to open source because I thought there were tons around, but some casual searching of the web finds nothing. – rzwitserloot Apr 14 '21 at 15:23
  • Follow up question: https://stackoverflow.com/questions/67095898/how-to-write-the-names-of-all-the-content-in-a-package-with-annotation-processor – seinecle Apr 14 '21 at 17:46
1

You can iterate the contents of any ZIP / JAR file using Files / NIO, but you need to access the ZIP filesystem. Then you can call Files.find or Files.walk on the contents of the ZIP / JAR archive.

For example this will print the contents of every Path in a jar:

Path zip = Path.of("your.jar");
BiPredicate<Path, BasicFileAttributes> predicate = (p,a) -> true;
try (FileSystem fs = FileSystems.newFileSystem(zip)) {
    for (Path root : fs.getRootDirectories()) {
        try(Stream<Path> stream = Files.find(root, Integer.MAX_VALUE, predicate)) {
            stream.forEach(System.out::println);
        }
    }
}

Once you have a Path object from the ZIP FileSystem, you can access the contents of the entries using NIO Files calls in the normal manner such as with Files.newInputStream or Files.copy.

DuncG
  • 12,137
  • 2
  • 21
  • 33