Java 使用 FileInputStream 在资源中加载文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19177882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Load a file in Resources with FileInputStream
提问by Diegolo
I know the safe way to open a file in the resources is:
我知道在资源中打开文件的安全方法是:
InputStream is = this.getClass().getResourceAsStream("/path/in/jar/file.name");
now the problem is that my file is a model for a decider in the Weka Wrapper package and the Decider classhas only a method:
现在的问题是我的文件是 Weka Wrapper 包中决策器的模型,而Decider 类只有一个方法:
public void load(File file) throws Exception
load takes the file and opens it as a FileInputStream. Do you see a workaround? I really would like to ship the model putting it in the resources. I was thinking to create a temporary file, write the content of the model in the temp file and then pass the temporary file to Weka, but it is so dirty.. other options?
load 获取文件并将其作为 FileInputStream 打开。你看到解决方法了吗?我真的很想将模型放入资源中。我想创建一个临时文件,将模型的内容写入临时文件中,然后将临时文件传递给 Weka,但它太脏了.. 其他选项?
采纳答案by René Link
I see 2 solutions:
我看到 2 个解决方案:
Solution 1
解决方案1
Read the classpath ressource to a temp file and delete it after you called load(File)
将类路径资源读取到临时文件并在调用后将其删除 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();
}
Solution 2
解决方案2
If the ClassLoader that loads the resource is a URLClassLoader you can try to find the absolute file name. But this only works if the resource you want exists as a file on the filesystem. It doesn't work if the file is contained in a jar.
如果加载资源的 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);
}
}
I would suggest to write a utility class that tries to find the absolute file through the class loader or if it can't get it this way uses the temp file approach as fallback.
我建议编写一个实用程序类,该类尝试通过类加载器查找绝对文件,或者如果无法以这种方式获取,则使用临时文件方法作为后备。
Or in a more object-oriented way:
或者以更面向对象的方式:
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;
}
}
}
You can also use a thrid party library like commons-vfsthat allows you to reference a file within a jar. E.g. jar:// arch-file-uri[! absolute-path]
. Since commons-vfs specifies an own FileObject
that represents a file you must still copy the content to a local java.io.File
to adapt to the Decider.load(File)
API.
您还可以使用像commons-vfs这样的第三方库,它允许您引用 jar 中的文件。例如jar:// arch-file-uri[! absolute-path]
。由于 commons-vfs 指定了一个FileObject
代表文件的自己,您仍然必须将内容复制到本地java.io.File
以适应Decider.load(File)
API。