类路径资源的java.nio.file.Path
是否有一个API来获取类路径资源(例如,我将从中获得什么)?理想情况下,我希望将新奇的类路径资源的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 {
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();
}