罐子里的文件对于春天不可见


103

所有

我使用以下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

在其根目录中有一个名为my.config的文件,该文件在我的spring-context.xml中是这样引用的:

<bean id="..." class="...">
    <property name="resource" value="classpath:my.config" />
</bean>

如果运行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
  • 类从罐子里加载
  • 从分离的罐子中加载spring和其他依赖项
  • 加载了Spring上下文(新的ClassPathXmlApplicationContext(“ spring-context / applicationContext.xml”))
  • my.properties加载到PropertyPlaceholderConfigurer(“ classpath:my.properties”)
  • 如果我将.config文件放在文件系统之外,然后将资源网址更改为“ file:”,则一切似乎都很好...

有小费吗?

Answers:


211

如果您的spring-context.xml和my.config文件位于不同的jar中,则需要使用 classpath*:my.config?。

更多信息 在这里

另外,请确保从jar文件内部加载时resource.getInputStream()不使用resource.getFile()


1
它们在同一个jar中,但是我尝试了具有相同结果的解决方案:java.io.FileNotFoundException:类路径资源[classpath *:my.config]无法解析为URL,因为它不存在
BTakacs 2013年

14
再次查看,您的某些调用代码(可能是BeanConfigurationFactoryBean)正在尝试加载java.io.File。文件是指文件系统上的文件,而jar中的条目则不是。调用代码应该使用resource.getInputStream代替从jar中加载。
sbk

57
...这就是答案...谢谢!在罐子内不要使用resource.getFile():-)
BTakacs,2013年

2
有机会出现“为什么?” 在罐子里不使用getFile()的背后?仅仅是文件在Jar内,因此“文件”就是jar文件吗?
RockMeetHardplace

8
而已。java.io.File以目录结构表示文件系统上的文件。Jar是一个java.io.File。但是该文件中的所有内容都超出了java.io.File的范围。就Java而言,在将其解压缩之前,JAR文件中的类与Word文档中的单词没有什么不同。
sbk 2013年

50

我知道这个问题已经回答了。但是,对于那些使用spring boot的人来说,此链接对我有帮助-https: //smarterco.de/java-load-file-classpath-spring-boot/

但是,resourceLoader.getResource("classpath:file.txt").getFile();是造成此问题和sbk的评论的原因:

而已。java.io.File以目录结构表示文件系统上的文件。Jar是一个java.io.File。但是该文件中的所有内容都超出了java.io.File的范围。就Java而言,在将其解压缩之前,JAR文件中的类与Word文档中的单词没有什么不同。

帮助我理解了为什么要使用它getInputStream()。现在对我有用!

谢谢!


37

在spring jar包中,我使用new ClassPathResource(filename).getFile(),它将引发异常:

无法解析为绝对文件路径,因为它不驻留在文件系统中:jar

但是使用new ClassPathResource(filename).getInputStream()可以解决此问题。原因是jar中的配置文件在操作系统的文件树中不存在,因此必须使用getInputStream()


2

使用Tomcat6.x时,我遇到了类似的问题,发现的建议都没有帮助。最后我删除了work(Tomcat)的文件夹,问题消失了。

我知道这是不合逻辑的,但出于文档目的...


1

我认为@sbk的答案是我们应该在春季启动环境中进行操作的方式(除了@Value(“ $ {classpath *:}))。 jar ..可能是我做错了。

但这可能是另一种方式,

InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);

1

我遇到的问题更加复杂,因为我有多个同名文件,一个在主Spring Boot jar中,而另一个在主fat jar中。我的解决方案是获取所有具有相同名称的资源,然后获得我需要按程序包名称进行过滤的资源。要获取所有文件:

ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);

0

我在递归地在Spring应用程序中加载资源时遇到问题,发现该问题是我应该使用的resource.getInputStream。这里是展示了如何递归在所有文件中读取一个例子config/myfilesjson文件。

范例.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 using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.