jar 中的文件在 spring 中不可见
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14876836/
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
File inside jar is not visible for spring
提问by BTakacs
All
全部
I created a jar file with the following MANIFEST.MF inside:
我创建了一个包含以下 MANIFEST.MF 的 jar 文件:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_25-b06 (Sun Microsystems Inc.)
Main-Class: my.Main
Class-Path: . lib/spring-core-3.2.0.M2.jar lib/spring-beans-3.2.0.M2.jar
In its root there is a file called my.config which is referenced in my spring-context.xml like this:
在它的根目录中有一个名为 my.config 的文件,它在我的 spring-context.xml 中被引用,如下所示:
<bean id="..." class="...">
<property name="resource" value="classpath:my.config" />
</bean>
If I run the jar, everything looks fine escept the loading of that specific file:
如果我运行 jar,除了加载该特定文件外,一切看起来都很好:
Caused by: java.io.FileNotFoundException: class path resource [my.config] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/work/my.jar!/my.config
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:205)
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:32)
at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:1)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 22 more
- classes are loaded the from inside the jar
- spring and other dependencies are loaded from separated jars
- spring context is loaded (new ClassPathXmlApplicationContext("spring-context/applicationContext.xml"))
- my.properties is loaded into PropertyPlaceholderConfigurer ("classpath:my.properties")
- if I put my .config file outside the file system, and change the resource url to 'file:', everything seems to be fine...
- 类是从 jar 内部加载的
- spring 和其他依赖项是从分离的 jars 加载的
- spring 上下文已加载(new ClassPathXmlApplicationContext("spring-context/applicationContext.xml"))
- my.properties 被加载到 PropertyPlaceholderConfigurer ("classpath:my.properties")
- 如果我将我的 .config 文件放在文件系统之外,并将资源 url 更改为 'file:',一切似乎都很好......
Any tips?
有小费吗?
回答by sbk
If your spring-context.xml and my.config files are in different jars then you will need to use classpath*:my.config?
如果您的 spring-context.xml 和 my.config 文件在不同的 jars 中,那么您将需要使用classpath*:my.config?
More info here
更多信息在这里
Also, make sure you are using resource.getInputStream()not resource.getFile()when loading from inside a jar file.
另外,请确保在从 jar 文件中加载时使用resource.getInputStream()not resource.getFile()。
回答by jmathewt
I know this question has already been answered. However, for those using spring boot, this link helped me - https://smarterco.de/java-load-file-classpath-spring-boot/
我知道这个问题已经有人回答了。但是,对于那些使用 spring boot 的人,这个链接帮助了我 - https://smarterco.de/java-load-file-classpath-spring-boot/
However, the resourceLoader.getResource("classpath:file.txt").getFile();was causing this problem and sbk's comment:
但是,resourceLoader.getResource("classpath:file.txt").getFile();导致此问题的原因是 sbk 的评论:
That's it. A java.io.File represents a file on the file system, in a directory structure. The Jar is a java.io.File. But anything within that file is beyond the reach of java.io.File. As far as java is concerned, until it is uncompressed, a class in jar file is no different than a word in a word document.
就是这样。java.io.File 表示文件系统上的一个目录结构中的文件。Jar 是一个 java.io.File。但是该文件中的任何内容都超出了 java.io.File 的范围。对java而言,在解压之前,jar文件中的类与word文档中的单词没有区别。
helped me understand why to use getInputStream() instead. It works for me now!
帮助我理解为什么使用 getInputStream() 代替。它现在对我有用!
Thanks!
谢谢!
回答by tao zeng
In the spring jar package, I use new ClassPathResource(filename).getFile(), which throws theexception:
在spring jar包中,我使用了新的ClassPathResource(filename).getFile(), which throws the异常:
cannot be resolved to absolute file path because it does not reside in the file system: jar
无法解析为绝对文件路径,因为它不在文件系统中:jar
But using new ClassPathResource(filename).getInputStream()will solve this problem. The reason is that the configuration file in the jar does not exist in the operating system's file tree,so must use getInputStream().
但是使用 newClassPathResource(filename).getInputStream()可以解决这个问题。原因是操作系统的文件树中不存在jar中的配置文件,所以必须使用getInputStream().
回答by takacsot
I had similar problem when using Tomcat6.x and none of the advices I found was helping.
At the end I deleted workfolder (of Tomcat) and the problem gone.
我在使用 Tomcat6.x 时遇到了类似的问题,我发现的建议都没有帮助。最后我删除了work文件夹(Tomcat)并且问题消失了。
I know it is illogical but for documentation purpose...
我知道这是不合逻辑的,但出于文档目的...
回答by Abhishek Chatterjee
The answer by @sbk is the way we should do it in spring-boot environment (apart from @Value("${classpath*:})), in my opinion. But in my scenario it was not working if the execute from standalone jar..may be I did something wrong.
在我看来,@sbk 的答案是我们应该在 spring-boot 环境中执行此操作的方式(@Value("${classpath*:}) 除外)。但在我的场景中,如果从独立执行,则它不起作用jar ..可能是我做错了什么。
But this can be another way of doing this,
但这可以是另一种方式,
InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);
回答by Brad Parks
I was having an issue recursively loading resources in my Spring app, and found that the issue was I should be using resource.getInputStream. Here's an example showing how to recursively read in all files in config/myfilesthat are jsonfiles.
我在 Spring 应用程序中递归加载资源时遇到问题,发现问题是我应该使用resource.getInputStream. 这里是展示了如何递归在所有文件中读取一个例子config/myfiles是json文件。
Example.java
例子.java
private String myFilesResourceUrl = "config/myfiles/**/";
private String myFilesResourceExtension = "json";
ResourceLoader rl = new ResourceLoader();
// Recursively get resources that match.
// Big note: If you decide to iterate over these,
// use resource.GetResourceAsStream to load the contents
// or use the `readFileResource` of the ResourceLoader class.
Resource[] resources = rl.getResourcesInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);
// Recursively get resource and their contents that match.
// This loads all the files into memory, so maybe use the same approach
// as this method, if need be.
Map<Resource,String> contents = rl.getResourceContentsInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);
ResourceLoader.java
资源加载器
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.StreamUtils;
public class ResourceLoader {
public Resource[] getResourcesInResourceFolder(String folder, String extension) {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
String resourceUrl = folder + "/*." + extension;
Resource[] resources = resolver.getResources(resourceUrl);
return resources;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public String readResource(Resource resource) throws IOException {
try (InputStream stream = resource.getInputStream()) {
return StreamUtils.copyToString(stream, Charset.defaultCharset());
}
}
public Map<Resource, String> getResourceContentsInResourceFolder(
String folder, String extension) {
Resource[] resources = getResourcesInResourceFolder(folder, extension);
HashMap<Resource, String> result = new HashMap<>();
for (var resource : resources) {
try {
String contents = readResource(resource);
result.put(resource, contents);
} catch (IOException e) {
throw new RuntimeException("Could not load resource=" + resource + ", e=" + e);
}
}
return result;
}
}
回答by Enrique Jiménez Flores
I was having an issue more complex because I have more than one file with same name, one is in the main Spring Boot jar and others are in jars inside main fat jar. My solution was getting all the resources with same name and after that get the one I needed filtering by package name. To get all the files:
我遇到了一个更复杂的问题,因为我有多个同名文件,一个在主 Spring Boot jar 中,其他在主 fat jar 中。我的解决方案是获取所有具有相同名称的资源,然后获取我需要按包名称过滤的资源。要获取所有文件:
ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);

