springboot运行jar包,实现复制jar包resources下文件、文件夹(可支持包含子文件夹)到指定的目录
背景:
以jar包运行时,获取文件目录时,会报错;
idea运行不会报错。
代码:
//复制文件夹到指定路径下
String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("").getPath()+ "/templates";
FileUtils.copyFolder(new File(srcFilePath), dir);
/*** 文件夹的复制* @param srcFile 源文件夹File对象* @param destFile 目标文件夹File对象* @throws IOException IOException*/public static void copyFolder(File srcFile, File destFile) throws IOException {//判断数据源File是否是文件if (srcFile.isDirectory()) {//在目的地下创建和数据源File名称一样的目录String srcFileName = srcFile.getName();File newFolder = new File(destFile, srcFileName);if (!newFolder.exists()) {newFolder.mkdir();}//获取数据源File下所有文件或者目录的File数组File[] listFiles = srcFile.listFiles();//遍历该File数组,得到每一个File对象for (File file : listFiles) {//把该File作为数据源File对象,递归调用复制文件夹的方法copyFolder(file, newFolder);}} else {//说明是文件,直接用字节流复制File newFile = new File(destFile, srcFile.getName());copyFile(srcFile, newFile);}}/*** 复制文件* @param srcFile 源文件* @param destFile 目标文件* @throws IOException IOException*/public static void copyFile(File srcFile, File destFile) throws IOException {BufferedInputStream bis = null;BufferedOutputStream bos = null;try {if (!destFile.getParentFile().exists()) {destFile.getParentFile().mkdirs();}if (!destFile.exists()) {destFile.createNewFile();}bis = new BufferedInputStream(new FileInputStream(srcFile));bos = new BufferedOutputStream(new FileOutputStream(destFile));int len;byte[] bys = new byte[1024];while ((len = bis.read(bys)) != -1) {bos.write(bys, 0, len);}} finally {if (null != bos) {try {bos.close();} catch (IOException e) {e.printStackTrace();}}if (null != bis) {try {bis.close();} catch (IOException e) {e.printStackTrace();}}}}
这行:bis = new BufferedInputStream(new FileInputStream(srcFile));
文件复制时,报错:
java.io.FileNotFoundException: file:/xxx/xxx.jar!/BOOT-INF/classes!/xxx/xxx (No such file or directory)
或
java.io.FileNotFoundException: file:\xxx\xxx.jar!\BOOT-INF\classes!\xxx\xxx (文件名、目录名或卷标语法不正确。)
问题产生原因:当我们使用文件路径访问文件时,该路径下的文件必须是可访问的,而jar文件本质是上是一个压缩文件,需要解压才能访问,所以程序会直接报错。
解决方案:
更改复制文件夹方式,不读文件路径,直接读取文件流。
以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这边使用resource.getDescription()进行获取文件路径,然后进行格式化处理。
FreeMarkerUtil工具类
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.ClassUtils;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;/*** 复制resource文件、文件夹*/
public class FreeMarkerUtil {/*** 复制path目录下所有文件,覆盖(jar)** @param path 文件目录 不能以/开头* @param newPath 新文件目录*/public static void copyFolderFromJarCover(String path, String newPath) throws IOException {if (!new File(newPath).exists()) {new File(newPath).mkdir();}if (path.contains("\\")) {path = path.replace("\\", "/");}if (path.startsWith("/")) {//以/开头,去掉/path = path.substring(1);}if (path.endsWith("/")) {//以/结尾,去掉/path = path.substring(0, path.length() - 1);}ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();//获取所有匹配的文件(包含根目录文件、子目录、子目录下的文件)Resource[] resources = resolver.getResources("classpath:" + path + "/**/");//打印有多少文件for (Resource resource : resources) {//文件名String filename = resource.getFilename();//以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("\\", "/");//保留 /xxx/xxxdescription = description.replaceAll("(.*\\[)|(]$)", "").trim();//以“文件目录”进行分割,获取文件相对路径String[] descriptions = description.split(path + "/");if (descriptions.length > 1) {//获取文件相对路径,/xxx/xxxString relativePath = descriptions[1];//新文件路径String newFilePath = newPath + "/" + relativePath;if (FreeMarkerUtil.isDirectory(filename)) {//文件夹if (!new File(newFilePath).exists()) {new File(newFilePath).mkdir();}} else {//文件InputStream stream = resource.getInputStream();write2File(stream, newFilePath);}}}}/*** 复制path目录下所有文件,不覆盖(jar)** @param path 文件目录 不能以/开头* @param newPath 新文件目录*/public static void copyFolderFromJar(String path, String newPath) throws IOException {if (!new File(newPath).exists()) {new File(newPath).mkdir();}if (path.contains("\\")) {path = path.replace("\\", "/");}if (path.startsWith("/")) {//以/开头,去掉/path = path.substring(1);}if (path.endsWith("/")) {//以/结尾,去掉/path = path.substring(0, path.length() - 1);}ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();//获取所有匹配的文件(包含根目录文件、子目录、子目录下的文件)Resource[] resources = resolver.getResources("classpath:" + path + "/**/");//打印有多少文件for (Resource resource : resources) {//文件名String filename = resource.getFilename();//以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("\\", "/");//保留 /xxx/xxxdescription = description.replaceAll("(.*\\[)|(]$)", "").trim();//以“文件目录”进行分割,获取文件相对路径String[] descriptions = description.split(path + "/");if (descriptions.length > 1) {//获取文件相对路径,/xxx/xxxString relativePath = descriptions[1];//新文件路径String newFilePath = newPath + "/" + relativePath;if (FreeMarkerUtil.isDirectory(filename)) {//文件夹if (!new File(newFilePath).exists()) {new File(newFilePath).mkdir();}} else {//文件File f = new File(newFilePath);if (!f.exists()) {InputStream stream = resource.getInputStream();write2File(stream, newFilePath);}}}}}/*** 复制文件(jar)** @param path 源文件路径* @param newPath 新文件路径*/public static void copyFileFromJar(String path, String newPath) throws IOException {//不读文件路径,直接读取文件流InputStream inputStream = ClassUtils.getDefaultClassLoader().getResourceAsStream(path);write2File(inputStream, newPath);}/*** 输入流写入文件** @param is 输入流* @param filePath 文件保存目录路径* @throws IOException IOException*/public static void write2File(InputStream is, String filePath) throws IOException {File destFile = new File(filePath);if (!destFile.getParentFile().exists()) {destFile.getParentFile().mkdirs();}if (!destFile.exists()) {destFile.createNewFile();}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();}/*** 判断是否为目录、文件夹* @param filename 文件名* @return boolean*/public static boolean isDirectory(String filename) {if (StringUtils.isBlank(filename)) {return false;}//有后缀,是文件boolean contains = filename.contains(".");if (contains) {return false;}//是文件夹return true;}/*** 判断是否为目录、文件夹* @param path 文件路径* @return boolean*/public static boolean isDirectoryFromPath(String path) {if (StringUtils.isBlank(path)) {return false;}String newPath = path.replace("\\", "/");if (newPath.contains("/")) {newPath = newPath.substring(newPath.lastIndexOf("/"));}//有后缀,是文件;boolean contains = newPath.contains(".");if (contains) {return false;}//是文件夹return true;}public static void main(String[] args) throws IOException {//文件夹复制String path = "templates";String newPath = "D:/tmp";FreeMarkerUtil.copyFolderFromJarCover(path, newPath);//文件复制String filePath = "application.properties";String newFilePath = "D:/tmp/application.properties";FreeMarkerUtil.copyFileFromJar(filePath, newFilePath);}}
文件复制
同样道理,以jar包运行也会报错。
解决方案:
//文件复制
String filePath = "application.properties";
String newFilePath = "D:/tmp/application.properties";
FreeMarkerUtil.copyFileFromJar(filePath, newFilePath);
/*** 复制文件(jar)** @param path 源文件路径* @param newPath 新文件路径*/public static void copyFileFromJar(String path, String newPath) throws IOException {//不读文件路径,直接读取文件流InputStream inputStream = ClassUtils.getDefaultClassLoader().getResourceAsStream(path);write2File(inputStream, newPath);}
相关文章:
springboot运行jar包,实现复制jar包resources下文件、文件夹(可支持包含子文件夹)到指定的目录
背景: 以jar包运行时,获取文件目录时,会报错; idea运行不会报错。 代码: //复制文件夹到指定路径下 String srcFilePath Thread.currentThread().getContextClassLoader().getResource("").getPath() &…...
Webpack Bundle Analyzer包分析器
当我们需要分析打包文件dist里哪些资源可以进一步优化时,就可以使用包分析器插件webpack-bundle-analyzer。NPM上的介绍是使用交互式可缩放树图可视化 webpack 输出文件的大小。 我的是vue2项目。 1、webpack-bundle-analyzer插件的安装 $ npm install --save-dev…...
SQL-----STUDENT
【学生信息表】 【宿舍信息表】 【宿舍分配表】 为了相互关联,我们需要在表中添加外键。在宿舍分配表中添加用于关联学生信息表的外键 student_id,以及用于关联宿舍信息表的外键 dormitory_id; sql代码 -- 创建学生信息表 CREATE TABLE st…...
OpenCV入门——图像视频的加载与展示一些API
文章目录 OpenCV创建显示窗口OpenCV加载显示图片OpenCV保存文件利用OpenCV从摄像头采集视频从多媒体文件中读取视频帧将视频数据录制成多媒体文件OpenCV控制鼠标关于[np.uint8](https://stackoverflow.com/questions/68387192/what-is-np-uint8) OpenCV中的TrackBar控件TrackBa…...
Control的Invoke和BeginInvoke
近日,被Control的Invoke和BeginInvoke搞的头大,就查了些相关的资料,整理如下。感谢这篇文章对我的理解Invoke和BeginInvoke的真正含义 。 (一)Control的Invoke和BeginInvoke 我们要基于以下认识: (1&#x…...
什么是OpenCL?
什么是OpenCL? 1.概述 OpenCL(Open Computing Language 开放计算语言)是一种开放的、免版税的标准,用于超级计算机、云服务器、个人计算机、移动设备和嵌入式平台中各种加速器的跨平台并行编程。OpenCL是由Khronos Group创建和管理的。OpenCL使应用程序…...
AdaBoost:提升机器学习的力量
一、介绍 机器学习已成为现代技术的基石,为从推荐系统到自动驾驶汽车的一切提供动力。在众多机器学习算法中,AdaBoost(Adaptive Boosting的缩写)作为一种强大的集成方法脱颖而出,为该领域的成功做出了重大贡献。AdaBoo…...
Pikachu(皮卡丘靶场)初识XSS(常见标签事件及payload总结)
目录 1、反射型xss(get) 2、反射性xss(post) 3、存储型xss 4、DOM型xss 5、DOM型xss-x XSS又叫跨站脚本攻击,是HTML代码注入,通过对网页注入浏览器可执行代码,从而实现攻击。 1、反射型xss(get) Which NBA player do you like? 由…...
一则DNS被重定向导致无法获取MySQL连接处理
同事反馈xwik应用端报java exception 获取MySQL连接超时无法连接到数据库实例 经过告警日志发现访问进来的IP地址数据库端无法被解析,这里可以知道问题出现在Dns配置上了 通过以上报错检查/etc/resolve.conf 发现namesever 被重定向设置成了114.114.114.114 域名 …...
Vue3中如何使用this
import { getCurrentInstance, ComponentInternalInstance } from vuesetup() {// as ComponetInternalInstance表示类型断言,ts时使用。否则报错,proxy为nullconst { proxy } getCurrentInstance() as ComponetInternalInstanceproxy.$parentproxy.$re…...
7.jvm对象内存布局
目录 概述对象里的三个区对象头验证代码控制台输出分析 验证2代码控制台输出 实例数据对其填充 访问对象结束 概述 jvm对象内存布局详解。 相关文章在此总结如下: 文章地址jvm基本知识地址jvm类加载系统地址双亲委派模型与打破双亲委派地址运行时数据区地址运行时数…...
U-boot(一):Uboot命令和tftp
本文主要基于S5PV210探讨uboot。 uboot 部署:uboot(180~400K的裸机程序)在Flash(可上电读取)、OS在FLash(nand) 启动过程:上电后先执行uboot、uboot初始化DDR和Flash,将OS从Flash中读到DDR中启动OS,uboot结束 特点:…...
代码随想录算法训练营第五十三天丨 动态规划part14
1143.最长公共子序列 思路 本题和动态规划:718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了,但要有相对顺序,即:"ace" 是 "abcde" 的子序列,但 "aec" 不是 &quo…...
pdf增强插件 Enfocus PitStop Pro 2022 mac中文版功能介绍
Enfocus PitStop Pro mac是一款 Acrobat 插件,主要用于 PDF 预检和编辑。这个软件可以帮助用户检查和修复 PDF 文件中的错误,例如字体问题、颜色设置、图像分辨率等。同时,Enfocus PitStop Pro 还提供了丰富的编辑工具,可以让用户…...
uniapp app tabbar 页面默认隐藏
1.在page.json 中找到tabbar visible 默认为true,设为false则是不显示 uni.setTabBarItem({ index: 1, //列表索引 visible:true //显示或隐藏 })...
深度学习 YOLO 实现车牌识别算法 计算机竞赛
文章目录 0 前言1 课题介绍2 算法简介2.1网络架构 3 数据准备4 模型训练5 实现效果5.1 图片识别效果5.2视频识别效果 6 部分关键代码7 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于yolov5的深度学习车牌识别系统实现 该项目较…...
即时通讯技术文集(第23期):IM安全相关文章(Part12) [共15篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第23 期。 [- 1 -] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计) [链接] http://www.52im.net/thread-283-…...
为什么UI自动化难做?—— 关于Selenium UI自动化的思考
在快速迭代的产品、团队中,UI自动化通常是一件看似美好,实际“鸡肋”(甚至绝大部分连鸡肋都算不上)的工具。原因不外乎以下几点: 1 效果有限 通常只是听说过,就想去搞UI自动化的团队,心里都认…...
Python小白之“没有名称为xlwings‘的模块”
题外话:学习和安装Python的第一个需求就是整理一个Excel,需要读取和写入Excel 背景:取到的模板代码,PyCharm本地运行报错:没有名称为xlwings的模块 解决办法:这类报模板找不到的错,即是模块缺…...
RK3588 学习教程1——获取linux sdk
上手rk3588前,需要先拥有一块开发板,这样可以少走很多弯路。个人推荐买一块itx3588j的板子。挺好用,接口丰富,可玩性高。 sdk可以直接在firefly官网下载,不用管什么版本,下载下来后直接更新即可࿰…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
