使用springboot时如何科学的读取classpath下的文件资源

我们一般都习惯把一些资源文件放到 /src/main/resources 中,然后在程序中用一些类库读取

准备一个文件在resources目录下

/src/main/resources
|-foo.txt

文件的内容

妖姬脸似花含露,玉树流光照后庭。

使用 ResourceUtils 读取

@GetMapping("/txt1")
public Object index () throws IOException {
	try {
		// 通过ResourceUtils获取classpath下的foo.txt文件,读取为 File 
		File file = ResourceUtils.getFile("classpath:foo.txt");
		try (InputStream inputStream = new FileInputStream(file)){
			// 读取到字节数组
			byte[] content = StreamUtils.copyToByteArray(inputStream);
			// 响应给客户端
			return ResponseEntity.status(HttpStatus.OK).header("Content-Type", "text/plain; charset=utf-8").body(content);
		}
	} catch (IOException e) {
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).header("Content-Type", "text/plain; charset=utf-8").body(e.getMessage());
	}
}

这是大家用的最多的工具类,它很方便,可以直接把classpath下的文件读取为File对象,在IDE中启动项目,访问,一切OK
image

但是一旦打包为jar文件,独立启动,访问的时候,这个方法就抛出异常

class path resource [foo.txt] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/eclipse/eclipse-jee-2020-12-R-win32-x86_64/project/springboot-demo/target/springboot-demo.jar!/BOOT-INF/classes!/foo.txt

打包后独立执行的jar文件,已经是一个独立的文件(压缩文件)了。ResourceUtils尝试从classpath路径下加载指定的文件,封装为File,但是foo.txt文件已经是这个文件的一部分。没办法把一个文件的一部分再封装成一个File对象。

使用 ClassPathResource 读取

@GetMapping("/txt2")
public Object index1 () throws IOException {
	try {
		ClassPathResource classPathResource = new ClassPathResource("foo.txt");
		try(InputStream inputStream = classPathResource.getInputStream()){
			byte[] content = StreamUtils.copyToByteArray(inputStream);
			return ResponseEntity.status(HttpStatus.OK).header("Content-Type", "text/plain; charset=utf-8").body(content);
		}
	} catch (IOException e) {
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).header("Content-Type", "text/plain; charset=utf-8").body(e.getMessage());
	}
}

看类名就知道,它就是专门读取classpath下资源的工具类。它并不会把资源封装为File对象,而是,返回Inputstream,用于读取内容。不论是在IDE中,还是打包为jar执行,都可以成功的读取到文件内容。

必选要封装为File对象

有些时候,需要调用第三方的一些类库,人家给的参数就必选是File,可以考虑用ClassPathResource 读取资源数据,复制到本地磁盘,返回封装本地磁盘的资源为File对象去调用第三方的类库。

相信科学!

1 Like

后庭 :heart_eyes: :heart_eyes: :heart_eyes: :heart_eyes: :heart_eyes: :heart_eyes:

你不对劲