Springboot jar運(yùn)行時(shí)如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中
背景
因?yàn)閳?zhí)行需要,需要把jar內(nèi)templates文件夾下的的文件夾及文件加壓到宿主機(jī)器的某個(gè)路徑下, 以便執(zhí)行對(duì)應(yīng)的腳本文件
PS: 通過(guò)類加載器等方式,直接getFile遍歷文件,在idea中運(yùn)行是沒(méi)問(wèn)題的,但是當(dāng)打包成jar運(yùn)行就會(huì)出現(xiàn)問(wè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
方式一
知道文件名的情況下,無(wú)需一層一層的遍歷,將文件路徑都指定好,然后根據(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",
"");
}
}
方式二
通過(guò)resource的方式,獲取文件的描述信息,然后根據(jù)描述信息,獲取文件的路徑信息,然后通過(guò)拷貝流文件,將文件最終拷貝到指定的路徑下
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 文件目錄 不能以/開(kāi)頭
* @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("\\", "/");
}
//保證沒(méi)有重復(fù)的/出現(xiàn)
path = path.replaceAll("(?<!\\G/|[^/])/+", "");
if (path.startsWith("/")) {
//以/開(kāi)頭,去掉/
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);
}
}
如果開(kāi)發(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("\\", "/");
}
//保證沒(méi)有重復(fù)的/出現(xiàn)
source = source.replaceAll("(?<!\\G/|[^/])/+", "");
if (source.startsWith("/")) {
//以/開(kāi)頭,去掉/
source = source.substring(1);
}
if (source.endsWith("/")) {
//以/結(jié)尾,去掉/
source = source.substring(0, source.length() - 1);
}
return source;
}
}通過(guò)這種方式,就能將正在運(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)文章
Springboot集成ClickHouse及應(yīng)用場(chǎng)景分析
這篇文章主要介紹了Springboot集成ClickHouse的實(shí)例代碼,本文通過(guò)應(yīng)用場(chǎng)景實(shí)例代碼介紹了整合springboot的詳細(xì)過(guò)程,感興趣的朋友跟隨小編一起看看吧2022-02-02
spring boot+thymeleaf+bootstrap實(shí)現(xiàn)后臺(tái)管理系統(tǒng)界面
這篇文章主要為大家詳細(xì)介紹了spring boot+thymeleaf+bootstrap簡(jiǎn)單實(shí)現(xiàn)后臺(tái)管理系統(tǒng)界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
SpringBoot加載讀取配置文件過(guò)程詳細(xì)分析
在實(shí)際的項(xiàng)目開(kāi)發(fā)過(guò)程中,我們經(jīng)常需要將某些變量從代碼里面抽離出來(lái),放在配置文件里面,以便更加統(tǒng)一、靈活的管理服務(wù)配置信息。所以本文將為大家總結(jié)一下SpringBoot加載配置文件的常用方式,需要的可以參考一下2023-01-01
解決mybatis 中collection嵌套collection引發(fā)的bug
這篇文章主要介紹了解決mybatis 中collection嵌套collection引發(fā)的bug,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
SpringBoot+Vue+Element-ui實(shí)現(xiàn)前后端分離
使用前后端分離的方式,可以減少代碼耦合,本文主要介紹了SpringBoot+Vue+Element-ui實(shí)現(xiàn)前后端分離,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
idea 安裝 Mybatis 開(kāi)發(fā)幫助插件 MyBatisCodeHelper-Pro 插件破解版的方法
MyBatisCodeHelper-Pro 插件可以幫助我們快速的開(kāi)發(fā) mybatis,這篇文章給大家介紹idea 安裝 Mybatis 開(kāi)發(fā)幫助插件 MyBatisCodeHelper-Pro 插件破解版的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2020-09-09
java對(duì)圖片進(jìn)行壓縮和resize縮放的方法
本篇文章主要介紹了java對(duì)圖片進(jìn)行壓縮和resize調(diào)整的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
java開(kāi)發(fā)主流定時(shí)任務(wù)解決方案全橫評(píng)詳解
這篇文章主要為大家介紹了java開(kāi)發(fā)主流定時(shí)任務(wù)解決方案全橫評(píng)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09

