背景
因为执行需要,需要把jar内templates文件夹下的的文件夹及文件加压到宿主机器的某个路径下, 以便执行对应的脚本文件
PS: 通过类加载器等方式,直接getFile遍历文件,在idea中运行是没问题的,但是当打包成jar运行就会出现问题,因为jar内文件的路径不是真实路径,会出现异常
java.io.FileNotFoundException: class path resource [xxx/xxx/] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:xxx.jar!/BOOT-INF/classes!/xxx/xxx
方式一
知道文件名的情况下,无需一层一层的遍历,将文件路径都指定好,然后根据流文件拷贝
- package com.aimsphm.practice;
-
- import lombok.extern.slf4j.Slf4j;
- import com.google.common.collect.Lists;
- import org.apache.commons.io.FileUtils;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.boot.SpringApplication;
- import org.springframework.util.ObjectUtils;
-
- import javax.annotation.PostConstruct;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.URL;
- import java.util.List;
-
- @Component
- public class App {
- public static void main(String[] args) {
- SpringApplication.run(App.class, args);
- }
-
- @Value("${customer.config.data-root:/usr/data/}")
- private String dataRoot;
-
-
- @PostConstruct
- public void initDatabase() {
- dataRoot = dataRoot.endsWith("/") ? dataRoot : dataRoot + "/";
- List
fileList = getFiles(); - fileList.stream().filter(x -> !ObjectUtils.isEmpty(x)).forEach(x -> {
- try {
- URL resource = App.class.getClassLoader().getResource(x);
- InputStream inputStream = resource.openStream();
- if (ObjectUtils.isEmpty(inputStream)) {
- return;
- }
- File file = new File(dataRoot + x);
- if (!file.exists()) {
- FileUtils.copyInputStreamToFile(inputStream, file);
- }
- } catch (IOException e) {
- log.error("失败:",e)
- }
- });
- }
-
- private List
getFiles() { - return Lists.newArrayList(
- "db/practice.db",
- "local-data/0/p-1.jpg",
- "local-data/0/p-2.jpg",
- "local-data/0/p-3.jpg",
- "local-data/0/p-4.jpg",
- "local-data/1/meter-1.png",
- "local-data/-1/yw-1.png",
- "local-data/sound/test.txt",
- "local-data/multi/1/meter-multi.jpg",
- "local-data/multi/-1/yewei.png",
- "");
- }
- }
方式二
通过resource的方式,获取文件的描述信息,然后根据描述信息,获取文件的路径信息,然后通过拷贝流文件,将文件最终拷贝到指定的路径下
- package com.example.demo.test;
-
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.core.io.support.ResourcePatternResolver;
- import org.springframework.stereotype.Component;
-
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
-
- /**
- * 复制resource文件、文件夹
- *
- * @author MILLA
- */
- @Component
- @Slf4j
- public class JarFileUtil {
-
-
- public void copyFolderFromJar() throws IOException {
- this.copyFolderFromJar("templates", "/usr/data/files");
- }
-
- /**
- * 复制path目录下所有文件到指定的文件系统中
- *
- * @param path 文件目录 不能以/开头
- * @param newPath 新文件目录
- */
- public void copyFolderFromJar(String path, String newPath) throws IOException {
- path = preOperation(path, newPath);
-
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- //获取所有匹配的文件(包含根目录文件、子目录、子目录下的文件)
- Resource[] resources = resolver.getResources("classpath:" + path + "/**");
- //打印有多少文件
- for (Resource resource : resources) {
- //文件名
- //以jar包运行时,不能使用resource.getFile()获取文件路径、判断是否为文件等,会报错:
- //java.io.FileNotFoundException: class path resource [xxx/xxx/] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:xxx.jar!/BOOT-INF/classes!/xxx/xxx
- //文件路径
- //file [/xxx/xxx]
- String description = resource.getDescription();
- description = description.replace("\\", "/");
- description = description.replace(path, "/");
- //保留 /xxx/xxx
- description = description.replaceAll("(.*\\[)|(]$)", "").trim();
- //以“文件目录”进行分割,获取文件相对路径
- //获取文件相对路径,/xxx/xxx
- //新文件路径
- String newFilePath = newPath + "/" + description;
- if (newFilePath.endsWith("/")) {
- File file = new File(newFilePath);
- //文件夹
- if (file.exists()) {
- boolean mkdir = file.mkdir();
- log.debug("路径[{}]创建是否成功状态:{} ", newFilePath, mkdir);
- }
-
- } else {
- //文件
- InputStream stream = resource.getInputStream();
- write2File(stream, newFilePath);
- }
- }
- }
-
- /**
- * 文件预处理
- *
- * @param path 原文件路径
- * @param newPath 目标路径
- * @return 新的路径字符串
- */
- private static String preOperation(String path, String newPath) {
- if (!new File(newPath).exists()) {
- boolean mkdir = new File(newPath).mkdir();
- log.debug("路径[{}]创建是否成功状态:{} ", newPath, mkdir);
- }
- if (path.contains("\\")) {
- path = path.replace("\\", "/");
- }
- //保证没有重复的/出现
- path = path.replaceAll("(?, "");
- if (path.startsWith("/")) {
- //以/开头,去掉/
- path = path.substring(1);
- }
- if (path.endsWith("/")) {
- //以/结尾,去掉/
- path = path.substring(0, path.length() - 1);
- }
- return path;
- }
-
- /**
- * 输入流写入文件
- *
- * @param is 输入流
- * @param filePath 文件保存目录路径
- * @throws IOException IOException
- */
- public static void write2File(InputStream is, String filePath) throws IOException {
- File destFile = new File(filePath);
- File parentFile = destFile.getParentFile();
- boolean mkdirs = parentFile.mkdirs();
- log.debug("路径[{}]创建是否成功状态:{} ", filePath, mkdirs);
- if (!destFile.exists()) {
- boolean newFile = destFile.createNewFile();
- log.debug("路径[{}]创建是否成功状态:{} ", destFile.getPath(), newFile);
- }
- OutputStream os = new FileOutputStream(destFile);
- int len = 8192;
- byte[] buffer = new byte[len];
- while ((len = is.read(buffer, 0, len)) != -1) {
- os.write(buffer, 0, len);
- }
- os.close();
- is.close();
- }
-
- public static void main(String[] args) throws IOException {
- //文件夹复制
- String path = "templates";
- String newPath = "D:/tmp";
- new JarFileUtil().copyFolderFromJar(path, newPath);
-
- }
-
- }
如果开发中使用一些文件操作依赖,可简化代码如下
- --文件依赖 -->
-
commons-fileupload -
commons-fileupload -
1.3.3 -
- package com.example.demo.test;
-
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.io.FileUtils;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.core.io.support.ResourcePatternResolver;
- import org.springframework.stereotype.Component;
-
- import javax.annotation.PostConstruct;
- import java.io.File;
-
- /**
- *
- * 功能描述:
- *
- *
- * @author MILLA
- * @version 1.0
- * @since 2024/05/31 16:30
- */
- @Slf4j
- @Component
- public class JarFileUtil{
- public static void main(String[] args) {
- JarFileUtilinit = new JarFileUtil();
- init.copyFile2Temp("//templates//shell//", "/usr/data/shell/files");
- }
-
- @PostConstruct
- public void copyFile2Temp() {
-
- }
-
- public void copyFile2Temp(String source, String target) {
- try {
- source = preOperation(source, target);
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- Resource[] resources = resolver.getResources(source + "/**");
- for (int i = 0; i < resources.length; i++) {
- Resource resource = resources[i];
- // resource.getFile() jar运行时候不能用该方法获取文件,因为jar的路径不对
- String description = resource.getDescription();
- description = description.replace("\\", "/");
- description = description.replace(source, "/");
- //保留 /xxx/xxx
- description = description.replaceAll("(.*\\[)|(]$)", "").trim();
- //以“文件目录”进行分割,获取文件相对路径
- //获取文件相对路径,/xxx/xxx
- //新文件路径
- String newFilePath = target + File.separator + description;
- File file = new File(newFilePath);
- if (newFilePath.endsWith("/")) {
- boolean mkdirs = file.mkdirs();
- log.debug("路径[{}]创建是否成功状态:{} ", newFilePath, mkdirs);
- } else {
- FileUtils.copyInputStreamToFile(resource.getInputStream(), file);
- }
- }
- } catch (Exception e) {
- log.error("文件拷贝异常:", e);
- }
- }
-
- private static String preOperation(String source, String target) {
- if (!new File(target).exists()) {
- boolean mkdir = new File(target).mkdir();
- log.debug("路径[{}]创建是否成功状态:{} ", target, mkdir);
- }
- if (source.contains("\\")) {
- source = source.replace("\\", "/");
- }
- //保证没有重复的/出现
- source = source.replaceAll("(?, "");
- if (source.startsWith("/")) {
- //以/开头,去掉/
- source = source.substring(1);
- }
- if (source.endsWith("/")) {
- //以/结尾,去掉/
- source = source.substring(0, source.length() - 1);
- }
- return source;
- }
- }
通过这种方式,就能将正在运行的jar中的文件,拷贝到指定的路径下,记录备查