Java.nio.file.Path for pathpath resource

Is there an API to get a classpath resource (for example, what I got from Class.getResource(String) ) like java.nio.file.Path ? Ideally, I would like to use the new Path APIs with class resources.

+110
java java-7 nio2
Mar 29 '13 at 23:41
source share
8 answers

This works for me:

 return Paths.get(ClassLoader.getSystemResource(resourceName).toURI()); 
+116
May 14 '14 at 11:59
source share

Assuming what you want to do, Files.lines (...) is called on the resource that comes from the class path - possibly from inside the jar.

Since Oracle has minimized the concept of when a path is a path without making getResource return a useful path if it is in a jar file, then you need to do the following:

 Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines(); 
+22
Sep 15 '15 at 6:57
source share

Turns out you can do this with the built-in Zip File System provider . However, passing the resource URI directly to Paths.get will not work; instead, you first need to create a zip file system for the jar file URI without a record name, and then access the record in that file system:

 static Path resourceToPath(URL resource) throws IOException, URISyntaxException { Objects.requireNonNull(resource, "Resource URL cannot be null"); URI uri = resource.toURI(); String scheme = uri.getScheme(); if (scheme.equals("file")) { return Paths.get(uri); } if (!scheme.equals("jar")) { throw new IllegalArgumentException("Cannot convert to Path: " + uri); } String s = uri.toString(); int separator = s.indexOf("!/"); String entryName = s.substring(separator + 2); URI fileURI = URI.create(s.substring(0, separator)); FileSystem fs = FileSystems.newFileSystem(fileURI, Collections.<String, Object>emptyMap()); return fs.getPath(entryName); } 

Update:

It has been rightly noted that the above code contains a resource leak, as the code opens a new FileSystem object but never closes it. The best approach is to pass a Consumer-like work object very similar to how Holgers answer does. Open the ZipFS file system long enough so that the employee can do everything he needs with the path (if the employee does not try to save the path object for future use), then close the file system.

+9
Mar 30 '13 at 11:26
source share

The most common solution is as follows:

 interface IOConsumer<T> { void accept(T t) throws IOException; } public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException { try { Path p=Paths.get(uri); action.accept(p); } catch(FileSystemNotFoundException ex) { try(FileSystem fs = FileSystems.newFileSystem( uri, Collections.<String,Object>emptyMap())) { Path p = fs.provider().getPath(uri); action.accept(p); } } } 

The main obstacle is the use of two possibilities: either to have an existing file system that we must use but not close (for example, with a file URI or Java 9s module repository) or open and thus safely close the file system ourselves (like zip / files jar).

Thus, the solution above encapsulates the actual action in the interface , handles both cases, then closes securely in the second case and works with Java 7 in Java 10. It checks if there is an open file system before opening a new one, therefore it also works in that in case another component of your application has already opened the file system for the same zip / jar file.

It can be used in all versions of Java above, for example, to list the contents of a package ( java.lang in the example) as Path s, for example:

 processRessource(Object.class.getResource("Object.class").toURI(), new IOConsumer<Path>() { public void accept(Path path) throws IOException { try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) { for(Path p: ds) System.out.println(p); } } }); 

With Java 8 or later, you can use lambda expressions or method references to represent the actual action, for example

 processRessource(Object.class.getResource("Object.class").toURI(), path -> { try(Stream<Path> stream = Files.list(path.getParent())) { stream.forEach(System.out::println); } }); 

do the same thing.




The final release of the Java 9s modular system violated the above code example. The JRE inconsistently returns the path /java.base/java/lang/Object.class for Object.class.getResource("Object.class") whereas it should be /modules/java.base/java/lang/Object.class . This can be fixed by adding the missing /modules/ when the parent path is reported as non-existent:

 processRessource(Object.class.getResource("Object.class").toURI(), path -> { Path p = path.getParent(); if(!Files.exists(p)) p = p.resolve("/modules").resolve(p.getRoot().relativize(p)); try(Stream<Path> stream = Files.list(p)) { stream.forEach(System.out::println); } }); 

Then it will work again with all versions and storage methods.

+9
Mar 15 '16 at 20:10
source share

I wrote a small helper method for reading Paths from your class resources. This is very convenient to use, because it needs only the class reference that you saved, as well as the name of the resource itself.

 public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException { URL url = resourceClass.getResource(resourceName); return Paths.get(url.toURI()); } 
+3
Sep 03 '14 at 19:42
source share

You cannot create a URI from resources inside a jar file. You can just write it to temp file and then use it (java8):

 Path path = File.createTempFile("some", "address").toPath(); Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING); 
+1
Oct 05 '16 at 18:54
source share

You need to define a file system for reading resources from a jar file, as indicated in https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html . I managed to read the resource from the jar file with the codes below:

 Map<String, Object> env = new HashMap<>(); try (FileSystem fs = FileSystems.newFileSystem(uri, env)) { Path path = fs.getPath("/path/myResource"); try (Stream<String> lines = Files.lines(path)) { .... } } 
0
Dec 02 '15 at 10:26
source share

Read file from resource folder using NIO in java8

 public static String read(String fileName) { Path path; StringBuilder data = new StringBuilder(); Stream<String> lines = null; try { path = Paths.get(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI()); lines = Files.lines(path); } catch (URISyntaxException | IOException e) { logger.error("Error in reading propertied file " + e); throw new RuntimeException(e); } lines.forEach(line -> data.append(line)); lines.close(); return data.toString(); } 
0
Mar 16 '18 at 6:26
source share



All Articles