Spring Resource
上
文件系统是编程不可避开的领域,因为我们总是有可能读文件、写文件。Spring Framework 作为完整的 Java 企业级解决方案,自然也有文件处理方案啦,那就是 spring Resource
在我们正式学习 Spring Resource 的时候,你还需要了解一下在Java 工程中文件的几种情况
-
文件在电脑某个位置,比如说
d:/mywork/a.doc
-
文件在工程目录下,比如说
mywork/toutiao.png
-
文件在工程的
src/main/resources
目录下,我们在 Maven 的知识里介绍过这是 Maven 工程存放文件的地方
第一种和第二种情况都是使用 File 对象就可以读写啦,第三种情况比较特殊,因为 Maven 执行 package 的时候,会把resources日录下的文件一起打包进 jar 包里(我们之前提到过 jar 是 Java 的压缩文件)。
显然在第三种情况,用 File 对象是读取不到的,因为文件已经在 jar里啦。
可以使用
import java.io.File;
/**
* Test
*/
public class Test {
public static void main(String[] args) {
File file = new File("mywork/readme.md");
if(file.exists()){
System.out.println("readme.md 文件存在");
}
File file2 = new File("src/main/resources/nani.jpeg");
if(file2.exists()){
System.out.println("nani.jpeg 文件存在");
}
}
}
大家看到控制台输出了两个文件,现在看起来两个文件都可以加载对把?但是呢,在企业中源代码是不可能和运行程序放在一起的,所以下面的工程才是真实的情况。
我们运行看一下,这时候你会发现 src/main/resources/nani.jpeg
图片找不到啦
大家可以下载 app-1.0-SNAPSHoT.jar
到本地电脑,然后用解压缩软件解压看看文件
咦???解压后,我们刚才那个图片在文件夹根目录下呢?并且src/main/java这些都没有啦。
这就是 Java 文件系统和计算机文件系统的差异,工程目录最后是要编译成 jar 文件的,jar文件是从 包路径 开始的。Maven 工程编译后,会自动去掉 src/main/java
、src/main/resources
录
OK,那么现在的问题就是如何读取 jar 内部的文件呢
再提醒一下:这类文件一般我们都是存放在src/main/resources目录的,会自动打包到 jar 文件内
classpath
在 Java 内部当中,我们一般把文件路径称为 classpath,所以读取内部的文件就是从 classpath 内读取,classpath 指定的文件不能解析成 File 对象,但是可以解析成 InputStream,我们借助 Java lO 就可以读取出来了
classpath 类似虚拟目录,它的根目录是从/
开始代表的是src/main/java
或者src/main/resources
录
我们来看一下如何使用 classpath 读取文件,这次我们在 resources 目录下存放一个 data.json
文件。
Java 拥有很多丰富的第三方类库给我们使用,读取文件,我们可以使用 commons-io 这个库来,需要我们在 pom.xml 下添加依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
public class Test {
public static void main(String[] args) {
// 读取 classpath 的内容
InputStream in = Test.class.getClassLoader().getResourceAsStream("data.json");
// 使用 commons-io 库读取文本
try {
String content = IOUtils.toString(in, "utf-8");
System.out.println(content);
} catch (IOException e) {
// IOUtils.toString 有可能会抛出异常,需要我们捕获一下
e.printStackTrace();
}
}
}
重点代码:
InputStream in = Test.class.getClassLoader().getResourceAsStream("data.json");
这段代码的含义就是从 Java 运行的类加载器(ClassLoader)实例中查找文件, Test.class
指的当前的 Test.java 编译后的 Java class 文件。记住这个代码格式就好,以后可能会经常用到,如果你记不住那 copy 也可以
ps:我在实现过程中遇到这样一个问题,当file
不在resources
里面的之后显示空指针异常
当将file
放置resources
下时正常运行
下
了解了 classpath 概念后,我想你肯定在想 Spring Resource 能做啥呢?请记住一点,Spring 擅长的就是封装各种服务
在 Spring 当中定义了一个
org.springframework.core.io.Resource
类来封装文件,这个类的优势在于可以支持普通的 File 也可以支持 classpath 文件。
并且在 Spring 中通过org.springframework.core.io.ResourceLoader
服务来提供任意文件的读写,你可以在任意的 Spring Bean 中引入 ResourceLoader
@Autowired
private ResourceLoader loader;
现在让我们来看一下在 Spring 当中如何读取文件,我们创建一个自
己的 FileService
public interface FileService {
String getContent(String name);
}
在看一下实现类
import fm.douban.service.FileService;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
@Service
public class FileServiceImpl implements FileService {
@Autowired
private ResourceLoader loader;
@Override
public String getContent(String name) {
try {
InputStream in = loader.getResource(name).getInputStream();
return IOUtils.toString(in,"utf-8");
} catch (IOException e) {
return null;
}
}
}
在看一下这个服务的调用,在启动类中:
FileService fileService = context.getBean(FileService.class);
String content = fileService.getContent("classpath:data/urls.txt");
System.out.println(content);
读取本地文件:
String content2 = fileService.getContent("file:mywork/readme.md");
System.out.println(content2);
这个
file:mywork/readme.md
代表的就是读取工程目录下文件mywork/readme.md
读取远程文件:
String content3 = fileService.getContent("https://blog.csdn.net/oageux/article/details/140505021?spm=1001.2014.3001.5501");
System.out.println(content3);