一、需求场景
有时候我们需要在项目中使用一些静态资源文件,比如城市信息文件 countries.xml
,在项目启动后读取其中的数据并初始化写进数据库中。
二、实现
静态资源文件 countries.xml
放在 src/main/resources
目录下
使用 Spring 的 ClassPathResource 来实现 :
- 1
- 2
- 3
ClassPathResource
类的注释如下:
Resource implementation for class path resources. Uses either a given ClassLoader or a given Class for loading resources.
Supports resolution as java.io.File if the class path resource resides in the file system, but not for resources in a JAR. Always supports resolution as URL.
翻译过来就是:
类路径资源的资源实现。使用给定的ClassLoader或给定的类来加载资源。
如果类路径资源驻留在文件系统中,则支持解析为 java.io.File,如果是JAR中的资源则不支持。始终支持解析为URL。
三、Jar 中资源文件
上面也提到了,如果静态资源文件在文件系统里,则支持解析为 java.io.File
,程序是能正常工作的。
到项目打包成 Jar
包放到服务器上运行就报找不到资源的错误了!
解决法案是:不获取 java.io.File
对象,而是直接获取输入流
:
- 1
- 2
说明:构造得到 resource
对象之后直接获取其输入流 resource.getInputStream()
。
---------------------------------------补充-----------------------------------------
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.
If you're using Spring framework then reading ClassPathResource into a String is pretty simple using Spring framework's 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);
}