Springboot jar運行時如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中
背景
因為執(zhí)行需要,需要把jar內(nèi)templates文件夾下的的文件夾及文件加壓到宿主機器的某個路徑下, 以便執(zhí)行對應(yīng)的腳本文件
PS: 通過類加載器等方式,直接getFile遍歷文件,在idea中運行是沒問題的,但是當打包成jar運行就會出現(xiàn)問題,因為jar內(nèi)文件的路徑不是真實路徑,會出現(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包運行時,不能使用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("路徑[{}]創(chuàng)建是否成功狀態(tài):{} ", newFilePath, mkdir); } } else { //文件 InputStream stream = resource.getInputStream(); write2File(stream, newFilePath); } } } /** * 文件預(yù)處理 * * @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("路徑[{}]創(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ā)中使用一些文件操作依賴,可簡化代碼如下
<!--文件依賴 --> <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運行時候不能用該方法獲取文件,因為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("路徑[{}]創(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; } }
通過這種方式,就能將正在運行的jar中的文件,拷貝到指定的路徑下,記錄備查
到此這篇關(guān)于Springboot jar運行時如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中的文章就介紹到這了,更多相關(guān)Springboot jar運行文件拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot 自定義數(shù)據(jù)源DruidDataSource代碼
這篇文章主要介紹了Spring Boot 自定義數(shù)據(jù)源DruidDataSource代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10Java使用poi組件導(dǎo)出Excel格式數(shù)據(jù)
這篇文章主要介紹了Java使用poi組件導(dǎo)出Excel格式數(shù)據(jù),需要的朋友可以參考下2020-02-02Java Web項目中Spring框架處理JSON格式數(shù)據(jù)的方法
Spring MVC是個靈活的框架,返回JSON數(shù)據(jù)的也有很多五花八門的方式,這里我們來整理一個最簡單的Java Web項目中Spring框架處理JSON格式數(shù)據(jù)的方法:2016-05-05MyBatis的各種查詢功能結(jié)果接收類型的選擇(推薦)
文章介紹了MyBatis中查詢結(jié)果的不同接收方式,包括單條數(shù)據(jù)和多條數(shù)據(jù)的處理方法,以及MyBatis的默認類型別名,感興趣的朋友跟隨小編一起看看吧2024-11-11