Java 作为 jar 运行时找不到类路径资源
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25869428/
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
Classpath resource not found when running as jar
提问by gyoder
Having this problem both in Spring Boot 1.1.5 and 1.1.6 - I'm loading a classpath resource using an @Value annotation, which works just fine when I run the application from within STS (3.6.0, Windows). However, when I run a mvn package and then try to run the jar, I get FileNotFound exceptions.
在 Spring Boot 1.1.5 和 1.1.6 中都有这个问题 - 我正在使用 @Value 注释加载类路径资源,当我从 STS(3.6.0,Windows)中运行应用程序时,它工作得很好。但是,当我运行 mvn 包然后尝试运行 jar 时,我收到 FileNotFound 异常。
The resource, message.txt, is in src/main/resources. I've inspected the jar and verified that it contains the file "message.txt" at the top level (same level as application.properties).
资源 message.txt 位于 src/main/resources 中。我检查了 jar 并验证它在顶层(与 application.properties 相同的级别)包含文件“message.txt”。
Here's the application:
这是应用程序:
@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());
}
}
}
The exception:
例外:
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
采纳答案by Andy Wilkinson
resource.getFile()
expects the resource itself to be available on the file system, i.e. it can't be nested inside a jar file. This is why it works when you run your application in STS but doesn't work once you've built your application and run it from the executable jar. Rather than using getFile()
to access the resource's contents, I'd recommend using getInputStream()
instead. That'll allow you to read the resource's content regardless of where it's located.
resource.getFile()
期望资源本身在文件系统上可用,即它不能嵌套在 jar 文件中。这就是为什么当您在 STS 中运行您的应用程序时它可以工作,但一旦您构建了您的应用程序并从可执行 jar 运行它就不起作用。getFile()
我建议getInputStream()
改为使用,而不是用于访问资源的内容。这将允许您阅读资源的内容,而不管它位于何处。
回答by Jae-il Lee
If you want to use a file:
如果要使用文件:
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);
}
回答by anubhava
If you're using Spring framework then reading ClassPathResource
into a String
is pretty simple using Spring framework's FileCopyUtils
:
如果您使用的是 Spring 框架,那么使用 Spring 框架的读ClassPathResource
入String
是非常简单的FileCopyUtils
:
String data = "";
ClassPathResource cpr = new ClassPathResource("static/file.txt");
try {
byte[] bdata = FileCopyUtils.copyToByteArray(cpr.getInputStream());
data = new String(bdata, StandardCharsets.UTF_8);
} catch (IOException e) {
LOG.warn("IOException", e);
}
回答by Ulises
I encountered this limitation too and created this library to overcome the issue: spring-boot-jar-resourcesIt basically allows you to register a custom ResourceLoader with Spring Boot that extracts the classpath resources from the JAR as needed, transparently.
我也遇到了这个限制,并创建了这个库来克服这个问题:spring-boot-jar-resources它基本上允许你使用 Spring Boot 注册一个自定义的 ResourceLoader,它根据需要从 JAR 中透明地提取类路径资源。
回答by zhuguowei
when spring boot project running as a jar and need read some file in classpath, I implement it by below code
当 spring boot 项目作为 jar 运行并且需要读取类路径中的一些文件时,我通过下面的代码实现它
Resource resource = new ClassPathResource("data.sql");
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
reader.lines().forEach(System.out::println);
回答by utkusonmez
Jersey needs to be unpacked jars.
泽西岛需要打开罐子。
<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>
回答by Tiago
I've create a ClassPathResourceReader class in a java 8 way to make easy read files from classpath
我以 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;
}
}
Utilization:
用途:
String content = new ClassPathResourceReader("data.sql").getContent();
回答by Jayshree Pancholi
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);
}
}
回答by Merzouk MENHOUR
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"))**
回答by aksh1618
Based on Andy's answerI used the following to get an input streams of all YAMLs under a directory and sub-directories in resources (Note that the path passed doesn't begin with /
):
根据安迪的回答,我使用以下内容获取资源中目录和子目录下所有 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();
}
}