Springboot jar運(yùn)行時(shí)如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中
背景
因?yàn)閳?zhí)行需要,需要把jar內(nèi)templates文件夾下的的文件夾及文件加壓到宿主機(jī)器的某個(gè)路徑下, 以便執(zhí)行對(duì)應(yīng)的腳本文件
PS: 通過類加載器等方式,直接getFile遍歷文件,在idea中運(yùn)行是沒問題的,但是當(dāng)打包成jar運(yùn)行就會(huì)出現(xiàn)問題,因?yàn)閖ar內(nèi)文件的路徑不是真實(shí)路徑,會(huì)出現(xiàn)異常
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
方式一
知道文件名的情況下,無需一層一層的遍歷,將文件路徑都指定好,然后根據(jù)流文件拷貝
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<String> 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<String> 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的方式,獲取文件的描述信息,然后根據(jù)描述信息,獲取文件的路徑信息,然后通過拷貝流文件,將文件最終拷貝到指定的路徑下
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;
/**
* 復(fù)制resource文件、文件夾
*
* @author MILLA
*/
@Component
@Slf4j
public class JarFileUtil {
public void copyFolderFromJar() throws IOException {
this.copyFolderFromJar("templates", "/usr/data/files");
}
/**
* 復(fù)制path目錄下所有文件到指定的文件系統(tǒng)中
*
* @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包運(yùn)行時(shí),不能使用resource.getFile()獲取文件路徑、判斷是否為文件等,會(huì)報(bào)錯(cuò):
//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();
//以“文件目錄”進(jìn)行分割,獲取文件相對(duì)路徑
//獲取文件相對(duì)路徑,/xxx/xxx
//新文件路徑
String newFilePath = newPath + "/" + description;
if (newFilePath.endsWith("/")) {
File file = new File(newFilePath);
//文件夾
if (file.exists()) {
boolean mkdir = file.mkdir();
log.debug("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", newFilePath, mkdir);
}
} else {
//文件
InputStream stream = resource.getInputStream();
write2File(stream, newFilePath);
}
}
}
/**
* 文件預(yù)處理
*
* @param path 原文件路徑
* @param newPath 目標(biāo)路徑
* @return 新的路徑字符串
*/
private static String preOperation(String path, String newPath) {
if (!new File(newPath).exists()) {
boolean mkdir = new File(newPath).mkdir();
log.debug("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", newPath, mkdir);
}
if (path.contains("\\")) {
path = path.replace("\\", "/");
}
//保證沒有重復(fù)的/出現(xiàn)
path = path.replaceAll("(?<!\\G/|[^/])/+", "");
if (path.startsWith("/")) {
//以/開頭,去掉/
path = path.substring(1);
}
if (path.endsWith("/")) {
//以/結(jié)尾,去掉/
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("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", filePath, mkdirs);
if (!destFile.exists()) {
boolean newFile = destFile.createNewFile();
log.debug("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", 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 {
//文件夾復(fù)制
String path = "templates";
String newPath = "D:/tmp";
new JarFileUtil().copyFolderFromJar(path, newPath);
}
}
如果開發(fā)中使用一些文件操作依賴,可簡(jiǎn)化代碼如下
<!--文件依賴 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>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;
/**
* <p>
* 功能描述:
* </p>
*
* @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("http://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運(yùn)行時(shí)候不能用該方法獲取文件,因?yàn)閖ar的路徑不對(duì)
String description = resource.getDescription();
description = description.replace("\\", "/");
description = description.replace(source, "/");
//保留 /xxx/xxx
description = description.replaceAll("(.*\\[)|(]$)", "").trim();
//以“文件目錄”進(jìn)行分割,獲取文件相對(duì)路徑
//獲取文件相對(duì)路徑,/xxx/xxx
//新文件路徑
String newFilePath = target + File.separator + description;
File file = new File(newFilePath);
if (newFilePath.endsWith("/")) {
boolean mkdirs = file.mkdirs();
log.debug("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", 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("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", target, mkdir);
}
if (source.contains("\\")) {
source = source.replace("\\", "/");
}
//保證沒有重復(fù)的/出現(xiàn)
source = source.replaceAll("(?<!\\G/|[^/])/+", "");
if (source.startsWith("/")) {
//以/開頭,去掉/
source = source.substring(1);
}
if (source.endsWith("/")) {
//以/結(jié)尾,去掉/
source = source.substring(0, source.length() - 1);
}
return source;
}
}通過這種方式,就能將正在運(yùn)行的jar中的文件,拷貝到指定的路徑下,記錄備查
到此這篇關(guān)于Springboot jar運(yùn)行時(shí)如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中的文章就介紹到這了,更多相關(guān)Springboot jar運(yùn)行文件拷貝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java如何獲取對(duì)象屬性及對(duì)應(yīng)值
這篇文章主要介紹了Java如何獲取對(duì)象屬性及對(duì)應(yīng)值,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Java整合Redis實(shí)現(xiàn)坐標(biāo)附近查詢功能
這篇文章主要介紹了Java整合Redis實(shí)現(xiàn)坐標(biāo)附近查詢,我們可以在redis服務(wù)器使用命令 help xxx 查看指令的具體用法,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2023-11-11
Spring Boot 自定義數(shù)據(jù)源DruidDataSource代碼
這篇文章主要介紹了Spring Boot 自定義數(shù)據(jù)源DruidDataSource代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
淺談Spring事務(wù)傳播行為實(shí)戰(zhàn)
這篇文章主要介紹了淺談Spring事務(wù)傳播行為實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Java使用poi組件導(dǎo)出Excel格式數(shù)據(jù)
這篇文章主要介紹了Java使用poi組件導(dǎo)出Excel格式數(shù)據(jù),需要的朋友可以參考下2020-02-02
手把手教你寫一個(gè)SpringBoot+gRPC服務(wù)
本文將在本地環(huán)境下搭建gRPC客戶端和服務(wù)端,并成功建立通訊發(fā)送消息的方式,從而幫助大家深入了解gRPC在Spring Boot項(xiàng)目中的應(yīng)用,有需要的小伙伴可以參考下2023-12-12
Java Web項(xiàng)目中Spring框架處理JSON格式數(shù)據(jù)的方法
Spring MVC是個(gè)靈活的框架,返回JSON數(shù)據(jù)的也有很多五花八門的方式,這里我們來整理一個(gè)最簡(jiǎn)單的Java Web項(xiàng)目中Spring框架處理JSON格式數(shù)據(jù)的方法:2016-05-05
MyBatis的各種查詢功能結(jié)果接收類型的選擇(推薦)
文章介紹了MyBatis中查詢結(jié)果的不同接收方式,包括單條數(shù)據(jù)和多條數(shù)據(jù)的處理方法,以及MyBatis的默認(rèn)類型別名,感興趣的朋友跟隨小編一起看看吧2024-11-11

