前段時間薄啥,在基于springboot開發(fā)過程中垄惧,遇到一個問題:程序需要讀取resource下的某個目錄的全部文件绰寞,而且需要能以File的方式讀取滤钱。但是, 打包后铜靶,springboot項目就成了jar包了他炊,讀取文件痊末,會報錯: ... cannot be resolved to absolute file path because it does not reside in the file system:jar:file: ....? 舌胶。
一般情況下,我們讀取resource下的某個文件辆它,可以這樣通過IO流的方式讀让誊浴:
Resource resource =new ClassPathResource(fileName);
InputStream is = resource.getInputStream();
當時,有些時候片吊,需要使用File:resource.getFile() 协屡,這時俏脊,在jar包下就會報上面的錯誤》粝可是爷贫,如果是文件夾怎么辦呢?
經(jīng)過網(wǎng)上的一番查詢补憾,確定了一個方案:把jar包中的文件漫萄,先存到一個臨時文件夾下,然后通過臨時文件夾盈匾,可以實現(xiàn)以File的方式讀取腾务,文件讀取完成后,刪除臨時文件目錄窑睁。
文件復制代碼如下:
import lombok.extern.log4j.Log4j2;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.*;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Log4j2
public class FileUtils {
? ? /**
? ? * 復制文件到目標目錄
? ? * @param resourcePath resource的文件夾路徑
? ? * @param tmpDir 臨時目錄
? ? * @param fileType 文件類型
? ? */
? ? public static void copyJavaResourceDir2TmpDir(String resourcePath, String tmpDir, FileType fileType) {
? ? ? ? Map<String, Object> fileMap = new HashMap<>();
? ? ? ? if (resourcePath.endsWith("/")) {
? ? ? ? ? ? resourcePath = resourcePath.substring(0, resourcePath.lastIndexOf("/"));
? ? ? ? }
? ? ? ? try {
? ? ? ? ? ? Enumeration resources = null;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? resources = Thread.currentThread().getContextClassLoader().getResources(resourcePath);
? ? ? ? ? ? } catch (Exception ex) {
? ? ? ? ? ? ? ? ex.printStackTrace();
? ? ? ? ? ? }
? ? ? ? ? ? if (resources == null || !resources.hasMoreElements()) {
? ? ? ? ? ? ? ? resources = FileUtils.class.getClassLoader().getResources(resourcePath);
? ? ? ? ? ? }
? ? ? ? ? ? while (resources.hasMoreElements()) {
? ? ? ? ? ? ? ? URL resource = (URL) resources.nextElement();
? ? ? ? ? ? ? ? if (resource.getProtocol().equals("file")) { // resource是文件
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? String[] split = resource.toString().split(":");
? ? ? ? ? ? ? ? String filepath = split[2];
? ? ? ? ? ? ? ? if (OperatingSystem.isWindows()) {
? ? ? ? ? ? ? ? ? ? filepath = filepath + ":" + split[3];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? String[] split2 = filepath.split("!");
? ? ? ? ? ? ? ? String zipFileName = split2[0];
? ? ? ? ? ? ? ? ZipFile zipFile = new ZipFile(zipFileName);
? ? ? ? ? ? ? ? Enumeration entries = zipFile.entries();
? ? ? ? ? ? ? ? while (entries.hasMoreElements()) {
? ? ? ? ? ? ? ? ? ? ZipEntry entry = (ZipEntry) entries.nextElement();
? ? ? ? ? ? ? ? ? ? String entryName = entry.getName();
? ? ? ? ? ? ? ? ? ? if (entry.isDirectory()) {
? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (entryName.contains(resourcePath) && entryName.endsWith(fileType.toString().toLowerCase())) {
? ? ? ? ? ? ? ? ? ? ? ? String dir = entryName.substring(0, entryName.lastIndexOf("/"));
? ? ? ? ? ? ? ? ? ? ? ? if (!dir.endsWith(resourcePath)) { // 目標路徑含有子目錄
? ? ? ? ? ? ? ? ? ? ? ? ? ? dir = dir.substring(dir.indexOf(resourcePath) + resourcePath.length() + 1);
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (dir.contains("/")) { // 多級子目錄
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? String[] subDir = dir.split("/");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Map<String, Object> map = fileMap;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? for (String d : subDir) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? map = makeMapDir(map, d);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? map.putAll(readOneFromJar(zipFile.getInputStream(entry), entryName));
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else { //一級子目錄
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (fileMap.get(dir) == null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fileMap.put(dir, new HashMap<String, Object>());
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ((Map<String, Object>) fileMap.get(dir))
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .putAll(readOneFromJar(zipFile.getInputStream(entry), entryName));
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? } else { // 目標路徑不含子目錄
? ? ? ? ? ? ? ? ? ? ? ? ? ? fileMap.putAll(readOneFromJar(zipFile.getInputStream(entry), entryName));
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? log.error("讀取resource文件異常:", e);
? ? ? ? } finally {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? // 寫到目標緩存路徑
? ? ? ? ? ? ? ? createFile(fileMap, tmpDir);
? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? log.error("創(chuàng)建臨時文件異常:", e);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? private static void createFile(Map<String, Object> fileMap, String targetDir) {
? ? ? ? fileMap.forEach((key, value) -> {
? ? ? ? ? ? if (value instanceof Map) {
? ? ? ? ? ? ? ? createFile((Map<String, Object>) value, targetDir + File.separator + key);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? createNewFile(targetDir + File.separator + key, value.toString());
? ? ? ? ? ? }
? ? ? ? });
? ? }
? ? public static void createNewFile(String filePath, String value) {
? ? ? ? try {
? ? ? ? ? ? File file = new File(filePath);
? ? ? ? ? ? if (!file.exists()) {
? ? ? ? ? ? ? ? File parentDir = file.getParentFile();
? ? ? ? ? ? ? ? if (!parentDir.exists()) {
? ? ? ? ? ? ? ? ? ? parentDir.mkdirs();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? file.createNewFile();
? ? ? ? ? ? }
? ? ? ? ? ? PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8")));
? ? ? ? ? ? out.write(value);
? ? ? ? ? ? out.flush();
? ? ? ? ? ? out.close();
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? log.error("創(chuàng)建文件異常:", e);
? ? ? ? }
? ? }
? ? private static Map<String, Object> makeMapDir(Map<String, Object> fileMap, String d) {
? ? ? ? if (fileMap.get(d) == null) {
? ? ? ? ? ? fileMap.put(d, new HashMap<String, Object>());
? ? ? ? }
? ? ? ? return (Map<String, Object>) fileMap.get(d);
? ? }
? ? public static Map<String, String> readOneFromJar(InputStream inputStream, String entryName) {
? ? ? ? Map<String, String> fileMap = new HashMap<>();
? ? ? ? try (Reader reader = new InputStreamReader(inputStream, "utf-8")) {
? ? ? ? ? ? StringBuilder builder = new StringBuilder();
? ? ? ? ? ? int ch = 0;
? ? ? ? ? ? while ((ch = reader.read()) != -1) {
? ? ? ? ? ? ? ? builder.append((char) ch);
? ? ? ? ? ? }
? ? ? ? ? ? String filename = entryName.substring(entryName.lastIndexOf("/") + 1);
? ? ? ? ? ? fileMap.put(filename, builder.toString());
? ? ? ? } catch (Exception ex) {
? ? ? ? ? ? log.error("讀取文件異常:", ex);
? ? ? ? }
? ? ? ? return fileMap;
? ? }
? ? public enum FileType {
? ? ? ? XSD, TXT, XLS, XLSX, DOC, DOCX, XML, SQL, PROPERTIES, SH
? ? }
}? ?
程序調用代碼如下:
String tmpDir = System.getProperty("user.dir") + File.separator +"tmp";
try {
? ? FileUtils.copyJavaResourceDir2TmpDir("xsd", tmpDir, FileUtils.FileType.XSD);
? ? loadXsd(new File(tmpDir));
} catch (Exception e) {
? ? logger.error("加載xsd文件異常:", e);
} finally {
? ? FileUtils.delete(tmpDir);
}
這樣,就不用每次部署實例的時候葵孤,都把需要文件和jar一起部署了担钮,方便多了。
OperatingSystem是Filnk中copy過來的代碼