在Spring Boot 1.1.5和1.1.6中都有这个问题 - 我正在使用@Value注释加载一个类路径资源,当我在STS中运行应用程序时,它运行正常(3.6.0,Windows) 。但是,当我运行mvn包然后尝试运行jar时,我得到了FileNotFound异常。
资源message.txt位于src / main / resources中。我检查了jar并验证它在顶层包含文件“message.txt”(与application.properties相同)。
以下是申请表:
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application implements CommandLineRunner {
private static final Logger logger = Logger.getLogger(Application.class);
@Value("${message.file}")
private Resource messageResource;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... arg0) throws Exception {
// both of these work when running as Spring boot app from STS, but
// fail after mvn package, and then running as java -jar
testResource(new ClassPathResource("message.txt"));
testResource(this.messageResource);
}
private void testResource(Resource resource) {
try {
resource.getFile();
logger.debug("Found the resource " + resource.getFilename());
} catch (IOException ex) {
logger.error(ex.toString());
}
}
}
例外:
c:\Users\glyoder\Documents\workspace-sts-3.5.1.RELEASE\classpath-resource-proble
m\target>java -jar demo-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.5.RELEASE)
2014-09-16 08:46:34.635 INFO 5976 --- [ main] demo.Application
: Starting Application on 8W59XV1 with PID 5976 (C:\Users\glyo
der\Documents\workspace-sts-3.5.1.RELEASE\classpath-resource-problem\target\demo
-0.0.1-SNAPSHOT.jar started by glyoder in c:\Users\glyoder\Documents\workspace-s
ts-3.5.1.RELEASE\classpath-resource-problem\target)
2014-09-16 08:46:34.640 DEBUG 5976 --- [ main] demo.Application
: Running with Spring Boot v1.1.5.RELEASE, Spring v4.0.6.RELEA
SE
2014-09-16 08:46:34.681 INFO 5976 --- [ main] s.c.a.AnnotationConfigA
pplicationContext : Refreshing org.springframework.context.annotation.Annotation
ConfigApplicationContext@1c77b086: startup date [Tue Sep 16 08:46:34 EDT 2014];
root of context hierarchy
2014-09-16 08:46:35.196 INFO 5976 --- [ main] o.s.j.e.a.AnnotationMBe
anExporter : Registering beans for JMX exposure on startup
2014-09-16 08:46:35.210 ERROR 5976 --- [ main] demo.Application
: java.io.FileNotFoundException: class path resource [message.
txt] cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/C:/Users/glyoder/Documents/workspace-sts-3.5.1.RELEASE/cl
asspath-resource-problem/target/demo-0.0.1-SNAPSHOT.jar!/message.txt
2014-09-16 08:46:35.211 ERROR 5976 --- [ main] demo.Application
: java.io.FileNotFoundException: class path resource [message.
txt] cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/C:/Users/glyoder/Documents/workspace-sts-3.5.1.RELEASE/cl
asspath-resource-problem/target/demo-0.0.1-SNAPSHOT.jar!/message.txt
2014-09-16 08:46:35.215 INFO 5976 --- [ main] demo.Application
: Started Application in 0.965 seconds (JVM running for 1.435)
2014-09-16 08:46:35.217 INFO 5976 --- [ Thread-2] s.c.a.AnnotationConfigA
pplicationContext : Closing org.springframework.context.annotation.AnnotationCon
figApplicationContext@1c77b086: startup date [Tue Sep 16 08:46:34 EDT 2014]; roo
t of context hierarchy
2014-09-16 08:46:35.218 INFO 5976 --- [ Thread-2] o.s.j.e.a.AnnotationMBe
anExporter : Unregistering JMX-exposed beans on shutdown
答案 0 :(得分:135)
resource.getFile()
期望资源本身在文件系统上可用,即它不能嵌套在jar文件中。这就是为什么它在您运行STS中的应用程序时有效,但是一旦您构建了应用程序并从可执行jar运行它就无法工作。我建议不要使用getFile()
来访问资源的内容,而是使用getInputStream()
。这将允许您阅读资源的内容,无论它位于何处。
答案 1 :(得分:33)
如果您想使用文件:
ClassPathResource classPathResource = new ClassPathResource("static/something.txt");
InputStream inputStream = classPathResource.getInputStream();
File somethingFile = File.createTempFile("test", ".txt");
try {
FileUtils.copyInputStreamToFile(inputStream, somethingFile);
} finally {
IOUtils.closeQuietly(inputStream);
}
答案 2 :(得分:5)
当spring boot项目作为jar运行并且需要在classpath中读取一些文件时,我通过下面的代码实现它
Resource resource = new ClassPathResource("data.sql");
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
reader.lines().forEach(System.out::println);
答案 3 :(得分:2)
我也遇到了这个限制并创建了这个库来克服这个问题:spring-boot-jar-resources 它基本上允许您使用Spring Boot注册自定义ResourceLoader,从而透明地从JAR中提取类路径资源。
答案 4 :(得分:2)
我以java 8方式创建一个ClassPathResourceReader类,以便从类路径中轻松读取文件
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import org.springframework.core.io.ClassPathResource;
public final class ClassPathResourceReader {
private final String path;
private String content;
public ClassPathResourceReader(String path) {
this.path = path;
}
public String getContent() {
if (content == null) {
try {
ClassPathResource resource = new ClassPathResource(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
content = reader.lines().collect(Collectors.joining("\n"));
reader.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
return content;
}
}
利用:
String content = new ClassPathResourceReader("data.sql").getContent();
答案 5 :(得分:1)
to get list of data from src/main/resources/data folder --
first of all mention your folder location in properties file as -
resourceLoader.file.location=data
inside class declare your location.
@Value("${resourceLoader.file.location}")
@Setter
private String location;
private final ResourceLoader resourceLoader;
public void readallfilesfromresources() {
Resource[] resources;
try {
resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("classpath:" + location + "/*.json");
for (int i = 0; i < resources.length; i++) {
try {
InputStream is = resources[i].getInputStream();
byte[] encoded = IOUtils.toByteArray(is);
String content = new String(encoded, Charset.forName("UTF-8"));
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
答案 6 :(得分:0)
泽西岛需要打开包装罐。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>com.myapp</groupId>
<artifactId>rest-api</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
答案 7 :(得分:0)
in spring boot :
1) if your file is ouside jar you can use :
@Autowired
private ResourceLoader resourceLoader;
**.resource(resourceLoader.getResource("file:/path_to_your_file"))**
2) if your file is inside resources of jar you can `enter code here`use :
**.resource(new ClassPathResource("file_name"))**
答案 8 :(得分:0)
基于安迪(Andy)的answer,我使用以下命令获取资源目录和子目录下所有YAML的输入流(请注意,传递的路径并非以/
开头):
private static Stream<InputStream> getInputStreamsFromClasspath(
String path,
PathMatchingResourcePatternResolver resolver
) {
try {
return Arrays.stream(resolver.getResources("/" + path + "/**/*.yaml"))
.filter(Resource::exists)
.map(resource -> {
try {
return resource.getInputStream();
} catch (IOException e) {
return null;
}
})
.filter(Objects::nonNull);
} catch (IOException e) {
logger.error("Failed to get definitions from directory {}", path, e);
return Stream.of();
}
}
答案 9 :(得分:0)
关于原始错误消息
无法解析为绝对文件路径,因为它不位于 文件系统
以下代码对于查找路径问题的解决方案可能会有所帮助:
Paths.get("message.txt").toAbsolutePath().toString();
由此,您可以确定应用程序期望丢失文件的位置。您可以在应用程序的main方法中执行此操作。
答案 10 :(得分:0)
我注意到的另一件重要的事情是,在运行应用程序时,它会忽略资源文件夹中文件/文件夹中的大写字母,而在以jar形式运行时,它不会忽略它。因此,如果您的文件位于Testfolder/messages.txt
@Autowired
ApplicationContext appContext;
// this will work when running the application, but will fail when running as jar
appContext.getResource("classpath:testfolder/message.txt");
因此,请不要在资源中使用大写字母,也不要在ClassPathResource的构造函数中添加这些大写字母:
appContext.getResource("classpath:Testfolder/message.txt");
答案 11 :(得分:0)
我遇到了同样的错误
InputStream inputStream =新的ClassPathResource(“ filename.ext”)。inputStream();
这应该在运行时解决FileNotFoundException