我要指出的一个问题是,如果相同的资源在多个jar文件中,该怎么办。
假设您想读取/org/node/foo.txt,但不是从一个文件中,而是从每个jar文件中读取。
我之前遇到过几次这个问题。
我曾希望在JDK 7中有人编写了一个classpath文件系统,但遗憾的是还没有。
Spring有Resource类,可以很好地加载类路径资源。
我编写了一个小型原型来解决从多个jar文件中读取资源的问题。该原型并未处理每个边缘情况,但它确实可以处理在jar文件中的目录中查找资源的情况。
我已经使用Stack Overflow很长时间了。这是我记得回答问题的第二个答案,所以请原谅我如果我讲得太长(这是我的天性)。
这是一个原型资源阅读器。该原型缺乏强大的错误检查。
我有两个设置的原型jar文件。
<pre>
<dependency>
<groupId>invoke</groupId>
<artifactId>invoke</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>node</groupId>
<artifactId>node</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
每个jar文件都有一个位于/org/node/下的名为resource.txt的文件。
这只是一个使用classpath://的处理程序原型。
我还在本地资源中为该项目添加了一个resource.foo.txt文件。
它会收集它们并将它们打印出来。
package com.foo;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* 原型资源读取器。
* 这个原型没有错误检查。
*
* 我有两个设置好的原型jar文件。
* <pre>
* <dependency>
* <groupId>invoke</groupId>
* <artifactId>invoke</artifactId>
* <version>1.0-SNAPSHOT</version>
* </dependency>
*
* <dependency>
* <groupId>node</groupId>
* <artifactId>node</artifactId>
* <version>1.0-SNAPSHOT</version>
* </dependency>
* </pre>
* 这些jar文件下都会有一个名为resource.txt的文件夹,路径是/org/node/。
* <br />
* 这只是一个处理类路径的handler演示.
* 本项目还有一个resource.foo.txt文件在本地资源中。
* <br />
*/
public class ClasspathReader {
public static void main(String[] args) throws Exception {
/* 这个项目包含了两个jar文件,每个jar文件都有一个位于/org/node/的资源文件。
表示为someResource。 */
String namespace = "resource";
//someResource是类路径。
String someResource = args.length > 0 ? args[0] :
//"classpath:///org/node/resource.txt"; It works with files
"classpath:///org/node/"; //It also works with directories
URI someResourceURI = URI.create(someResource);
System.out.println("URI of resource = " + someResourceURI);
someResource = someResourceURI.getPath();
System.out.println("PATH of resource =" + someResource);
boolean isDir = !someResource.endsWith(".txt");
/** 类路径下的资源文件实际上并不以“/”开头。
* 逻辑上是这样,但实际上需要去掉它。
* 这是类路径资源的已知行为。
* 如果资源文件在JAR文件中,则使用斜杠(/)。
* 通过去掉起始斜杠,可以在所有情况下正常工作。
*/
if (someResource.startsWith("/")) {
someResource = someResource.substring(1);
}
/* 使用ClassLoader查找具有该名称的所有资源。
查找匹配所需位置的所有资源。 */
Enumeration resources = null;
/* 首先检查上下文类加载器。如果有可用的,请始终使用此处。 */
try {
resources =
Thread.currentThread().getContextClassLoader().getResources(someResource);
} catch (Exception ex) {
ex.printStackTrace();
}
if (resources == null || !resources.hasMoreElements()) {
resources = ClasspathReader.class.getClassLoader().getResources(someResource);
}
//现在迭代类路径下资源的URL
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
/* 如果资源是文件,则可以使用正常机制来扫描目录。 */
if (resource.getProtocol().equals("file")) {
//如果是文件,则可以用普通的方式处理它。
handleFile(resource, namespace);
continue;
}
System.out.println("Resource " + resource);
/* 将字符串拆分为以下格式:
jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/
到这个
this /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar
和这个
/org/node/
*/
String[] split = resource.toString().split(":");
您可以在此处查看完整示例及样本输出。