Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
类路径资源的java.nio.file.Path_Java_Java 7_Nio2 - Fatal编程技术网

类路径资源的java.nio.file.Path

类路径资源的java.nio.file.Path,java,java-7,nio2,Java,Java 7,Nio2,是否有一个API来获取类路径资源(例如,我将从中获得什么)?理想情况下,我希望将新奇的Pathapi与类路径资源一起使用。事实证明,在内置的帮助下,您可以做到这一点。但是,将资源URI直接传递到路径。get将不起作用;相反,必须首先为jar URI创建一个没有条目名称的zip文件系统,然后引用该文件系统中的条目: static Path resourceToPath(URL resource) throws IOException, URISyntaxException {

是否有一个API来获取类路径资源(例如,我将从中获得什么)?理想情况下,我希望将新奇的
Path
api与类路径资源一起使用。

事实证明,在内置的帮助下,您可以做到这一点。但是,将资源URI直接传递到
路径。get
将不起作用;相反,必须首先为jar URI创建一个没有条目名称的zip文件系统,然后引用该文件系统中的条目:

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);
}
静态路径资源路径(URL资源)
抛出一个异常,
URISyntaxException{
requirennull(资源,“资源URL不能为空”);
URI=resource.toURI();
字符串scheme=uri.getScheme();
if(scheme.equals(“文件”)){
返回路径get(uri);
}
如果(!scheme.equals(“jar”)){
抛出新的IllegalArgumentException(“无法转换为路径:“+uri”);
}
字符串s=uri.toString();
int separator=s.indexOf(!/”;
String entryName=s.substring(分隔符+2);
urifileuri=URI.create(s.substring(0,分隔符));
FileSystem fs=FileSystems.newFileSystem(fileURI,
Collections.emptyMap());
返回fs.getPath(entryName);
}
更新:

有人正确地指出,上面的代码包含一个资源泄漏,因为该代码打开了一个新的文件系统对象,但从未关闭它。最好的方法是传递一个类似消费者的worker对象,就像霍尔格的答案那样。打开ZipFS文件系统的时间足以让工作人员对路径执行任何需要执行的操作(只要工作人员不尝试存储路径对象以供以后使用),然后关闭文件系统。

这一点对我很有用:

return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());

我编写了一个小助手方法来从类资源中读取路径。它使用起来非常方便,因为它只需要存储资源的类的引用以及资源本身的名称

public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
    URL url = resourceClass.getResource(resourceName);
    return Paths.get(url.toURI());
}  
public静态路径getResourcePath(类resourceClass,字符串resourceName)抛出URISyntaxException{
URL=resourceClass.getResource(resourceName);
返回path.get(url.toURI());
}  

猜测您想要做的是调用来自类路径的资源上的Files.lines(…),可能来自jar中

由于Oracle不让getResource返回一个可用的路径(如果它驻留在jar文件中),从而混淆了路径是路径的概念,因此您需要做的是这样的事情:

Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
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);
        }
    }
});
Stream=new BufferedReader(新的InputStreamReader(ClassLoader.getSystemResourceAsStream(“/filename.txt”)).lines();

您需要定义文件系统以从jar文件中读取资源,如中所述。我成功地从jar文件中读取资源,代码如下:

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)) {
            ....
        }
    }
Map env=new HashMap();
try(FileSystem fs=FileSystems.newFileSystem(uri,env)){
Path Path=fs.getPath(“/Path/myResource”);
try(流行=文件。行(路径)){
....
}
}

最通用的解决方案如下:

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);
        }
    }
}
对于Java8或更新版本,您可以使用lambda表达式或方法引用来表示实际操作,例如

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

然后,它将再次适用于所有版本和存储方法。

您不能从jar文件中的资源创建URI。您只需将其写入临时文件,然后使用它(java8):


在java8中,使用NIO从资源文件夹读取文件

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();
    }
公共静态字符串读取(字符串文件名){
路径;
StringBuilder数据=新的StringBuilder();
流线=空;
试一试{
path=path.get(Thread.currentThread().getContextClassLoader().getResource(fileName.toURI());
行=文件。行(路径);
}捕获(URISyntaxException | IOException e){
logger.error(“读取属性文件时出错”+e);
抛出新的运行时异常(e);
}
line.forEach(line->data.append(line));
行。关闭();
返回data.toString();
}

好吧,采用长路径(双关语),您有
路径。get(URI)
,然后是'URL.toURI()
,最后是
getResource()`返回
URL
。你也许可以把它们连在一起。但还没有尝试过。请注意新创建的fs。使用同一jar的第二个调用将抛出一个异常,抱怨已经存在的文件系统。最好执行try(文件系统fs=…){return fs.getPath(entryName);}或者如果希望缓存此文件,则执行更高级的处理。目前的形式是有风险的。除了潜在的非封闭新文件系统的问题外,关于方案之间关系的假设、打开新文件系统的必要性以及对URI内容的困惑限制了解决方案的实用性。我已经建立了一个模型,它展示了一种通用的方法,可以简化操作,同时处理新的方案,比如新的Java9类存储。当应用程序中的其他人已经打开文件系统时(或者为同一个jar调用了两次该方法),它也会起作用。根据此解决方案的使用情况,非关闭的
newFileSystem
可能会导致多个资源永远处于打开状态。尽管@raisercostin Addendment在尝试创建已创建的文件系统时避免了错误,但如果尝试使用返回的
路径
,您将获得
ClosedFileSystemException
@Holger响应对我来说很好。我不会关闭
文件系统。如果从Jar加载资源,然后创建所需的
文件系统
文件系统
还允许您从同一Jar加载其他资源。另外,一旦创建了新的
文件系统
,您可以尝试使用
路径再次加载资源。get(Path)
,实现将自动使用新的
文件系统
。即您这样做
Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
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();
    }