java.nio.file.Path for a classpath resource

后端 未结 8 947
自闭症患者
自闭症患者 2020-11-28 02:55

Is there an API to get a classpath resource (e.g. what I\'d get from Class.getResource(String)) as a java.nio.file.Path? Ideally, I\'d like to use the fancy new Path<

相关标签:
8条回答
  • 2020-11-28 03:19

    Guessing that what you want to do, is call Files.lines(...) on a resource that comes from the classpath - possibly from within a jar.

    Since Oracle convoluted the notion of when a Path is a Path by not making getResource return a usable path if it resides in a jar file, what you need to do is something like this:

    Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
    
    0 讨论(0)
  • 2020-11-28 03:20

    You can not create URI from resources inside of the jar file. You can simply write it to the 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);
    
    0 讨论(0)
  • 2020-11-28 03:26

    I wrote a small helper method to read Paths from your class resources. It is quite handy to use as it only needs a reference of the class you have stored your resources 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());
    }  
    
    0 讨论(0)
  • 2020-11-28 03:29

    This one works for me:

    return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());
    
    0 讨论(0)
  • 2020-11-28 03:31

    You need to define the Filesystem to read resource from jar file as mentioned in https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html. I success to read resource from jar file with below codes:

    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 讨论(0)
  • 2020-11-28 03:41

    It turns out you can do this, with the help of the built-in Zip File System provider. However, passing a resource URI directly to Paths.get won't work; instead, one must first create a zip filesystem for the jar URI without the entry name, then refer to the entry in that filesystem:

    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’s been rightly pointed out that the above code contains a resource leak, since the code opens a new FileSystem object but never closes it. The best approach is to pass a Consumer-like worker object, much like how Holger’s answer does it. Open the ZipFS FileSystem just long enough for the worker to do whatever it needs to do with the Path (as long as the worker doesn’t try to store the Path object for later use), then close the FileSystem.

    0 讨论(0)
提交回复
热议问题