我看到了 2 个解决方案:
解决方案 1
将类路径资源读取到临时文件并在调用后将其删除load(File)
InputStream cpResource = this.getClass().getClassLoader().getResourceAsStream("file.name");
File tmpFile = File.createTempFile("file", "temp");
FileUtils.copyInputStreamToFile(cpResource, tmpFile); // FileUtils from apache-io
try {
decider.load(tmpFile);
} finally {
tmpFile.delete();
}
解决方案 2
如果加载资源的 ClassLoader 是 URLClassLoader,您可以尝试查找绝对文件名。但这仅在您想要的资源作为文件存在于文件系统上时才有效。如果文件包含在 jar 中,则它不起作用。
ClassLoader classLoader = this.getClass().getClassLoader();
if(classLoader instanceof URLClassLoader){
URLClassLoader urlClassLoader = URLClassLoader.class.cast(classLoader);
URL resourceUrl = urlClassLoader.findResource("file.name");
if("file".equals(resourceUrl.getProtocol())){
URI uri = resourceUrl.toURI();
File file = new File(uri);
decider.load(file);
}
}
我建议编写一个实用程序类,尝试通过类加载器查找绝对文件,或者如果无法以这种方式获取它,则使用临时文件方法作为后备。
或者以更面向对象的方式:
public class FileResourceTest {
public static void main(String[] args) throws IOException {
File resourceAsFile = getResourceAsFile("file.name");
System.out.println(resourceAsFile);
}
private static File getResourceAsFile(String resource) throws IOException {
ClassLoader cl = FileResourceTest.class.getClassLoader();
File file = null;
FileResource fileResource = new URLClassLoaderFileResource(cl, resource);
try {
file = fileResource.getFile();
} catch (IOException e) {
fileResource = new ClasspathResourceFileResource(cl, resource);
file = fileResource.getFile();
}
return file;
}
public static interface FileResource {
public File getFile() throws IOException;
}
public static class ClasspathResourceFileResource implements FileResource {
private ClassLoader cl;
private String resource;
public ClasspathResourceFileResource(ClassLoader cl, String resource) {
this.cl = cl;
this.resource = resource;
}
public File getFile() throws IOException {
InputStream cpResource = cl.getResourceAsStream(resource);
File tmpFile = File.createTempFile("file", "temp");
FileUtils.copyInputStreamToFile(cpResource, tmpFile);
tmpFile.deleteOnExit();
return tmpFile;
}
}
public static class URLClassLoaderFileResource implements FileResource {
private ClassLoader cl;
private String resource;
public URLClassLoaderFileResource(ClassLoader cl, String resourcePath) {
this.cl = cl;
this.resource = resourcePath;
}
public File getFile() throws IOException {
File resourceFile = null;
if (cl instanceof URLClassLoader) {
URLClassLoader urlClassLoader = URLClassLoader.class.cast(cl);
URL resourceUrl = urlClassLoader.findResource(resource);
if ("file".equals(resourceUrl.getProtocol())) {
try {
URI uri = resourceUrl.toURI();
resourceFile = new File(uri);
} catch (URISyntaxException e) {
IOException ioException = new IOException(
"Unable to get file through class loader: "
+ cl);
ioException.initCause(e);
throw ioException;
}
}
}
if (resourceFile == null) {
throw new IOException(
"Unable to get file through class loader: " + cl);
}
return resourceFile;
}
}
}
您还可以使用第三方库,例如commons-vfs,它允许您引用 jar 中的文件。例如jar:// arch-file-uri[! absolute-path]
。由于 commons-vfs 指定了一个FileObject
代表文件的自己,因此您仍然必须将内容复制到本地java.io.File
以适应Decider.load(File)
API。
编辑
这很有帮助!较新版本的 java 中是否有任何已经支持此要求的内容?
即使我没有查看每个新版本的每个类,我也会说不。因为类路径资源并不总是文件。例如,它可以是 jar 中的文件,甚至是远程资源。想想java程序员很久以前使用的applet。因此,类路径及其资源的概念不受本地文件系统的约束。这显然是一件好事,因为您几乎可以从每个 URL 加载类,这使得它更加灵活。但这种灵活性也意味着您必须阅读资源并在需要File
.
但也许像我上面展示的那样的某种实用程序代码会将其放入 JRE。也许它已经在那里了。如果是这样,请发表评论并让我们都知道。