臨時接到一個需求說讓根據(jù)按照下面的這個圖片的結(jié)構(gòu)來打包下載指定位置下的文件到指定位置!
實現(xiàn)思路:
1.把已經(jīng)實現(xiàn)的樹形結(jié)構(gòu)的代碼進行調(diào)用,拿到他的數(shù)據(jù)進行創(chuàng)建對應(yīng)的文件夾
2.因為結(jié)構(gòu)下方的文件沒有特別直觀的數(shù)據(jù)庫中的關(guān)聯(lián)關(guān)系,所以還需要對于管理關(guān)系進行梳理
3.創(chuàng)建好階級文件,然后調(diào)用網(wǎng)上找的工具類打包成為rar壓縮包,然后把路勁交給前端進行調(diào)用下載
調(diào)用數(shù)據(jù),然后傳遞給創(chuàng)建文件方法進行實現(xiàn):
/**
* 打包佐證成果文件,壓縮成為壓縮包!
*
* @param projectId
* @param departId
*/
@ApiOperation(value = "打包佐證成果文件", notes = "佐證與成果-打包佐證成果文件")
@RequestMapping("/exportZip")
public Result<?> exportZip(@RequestParam(name = "projectId", required = false) String projectId, @RequestParam(name = "departId", required = true) String departId) {
// 獲取樹形結(jié)構(gòu)
Result<List<SelectTreeMoneyModel>> loadAllTreeRoot = this.loadAllTreeRoot(projectId, departId);
// 下載壓縮文件,將獲取到的樹形結(jié)構(gòu),傳遞到實現(xiàn)類進行解析跟實現(xiàn)
String downloadZipFile = downloadZipFile(loadAllTreeRoot, "佐證跟成果", "/");
return Result.ok(downloadZipFile);
}
遞歸的創(chuàng)建子集文件夾,然后調(diào)用工具類進行壓縮成為壓縮包文件,注:刪除文件必須捋清楚然后進行使用,其實不刪除也只會在指定的位置生成一份,所以我這邊沒有進行使用!
/**
* 遞歸的創(chuàng)建子集文件夾
*
* @param data
* @param rootFile
*/
private void mkdirsChild(List<SelectTreeMoneyModel> data, File rootFile) {
for (SelectTreeMoneyModel datum : data) {
// 創(chuàng)建一個file實例對象,指向文件路徑(存放照片的根目錄)
File childs = new File(rootFile, datum.getTitle());
if (!childs.exists()) {
childs.mkdirs();
}
// 判斷如果下面還有子節(jié)點,如果有則調(diào)用自身
if (!datum.isLeaf()) {
mkdirsChild(datum.getChildren(), childs);
}
// 如果下面沒有子節(jié)點,則進行判斷下面是否有附件,如果有附件則進行下載到指定的文件夾內(nèi)。
List<ProjectResult> results = iProjectResultService.list(new LambdaQueryWrapper<ProjectResult>().eq(ProjectResult::getTypeId, datum.getKey()));
if (ObjectUtils.isNotEmpty(results)) {
for (ProjectResult result : results) {
List<ProjectTaskContent> projectTaskContents = projectTaskContentService.list(new LambdaQueryWrapper<ProjectTaskContent>().eq(ProjectTaskContent::getResultId, result.getId()));
for (ProjectTaskContent projectTaskContent : projectTaskContents) {
// 判斷附件表不是空的,則進行下載文件到對應(yīng)的文件夾下
if (ObjectUtils.isNotEmpty(projectTaskContents)) {
RestTemplate restTemplate = new RestTemplate();
// 配置文件進行讀取
try {
ResponseEntity responseEntity = restTemplate.exchange(url + projectTaskContent.getFilePath(), HttpMethod.GET, null, byte[].class);
byte[] fileContent = (byte[]) responseEntity.getBody();
// 利用 File 對象,然后使用 getName() 方法獲取文件名(不包括路徑)。
File file = new File(projectTaskContent.getName());
String filenameWithoutPrefix = file.getName();
Files.write(Paths.get(childs + "\\" + filenameWithoutPrefix), fileContent);
} catch (IOException e) {
e.getMessage();
throw new RuntimeException(e);
}
}
}
}
}
}
}
/**
* 下載壓縮文件
*
* @param data 數(shù)據(jù)集合【key:分類名稱,value:照片信息集合(key:照片名稱,value:照片下載路徑)】
* @param fileStr 照片存放的文件路徑
* @param zipFileStr 壓縮文件的路徑(加后綴名)
*/
public String downloadZipFile(Result<List<SelectTreeMoneyModel>> data, String fileStr, String zipFileStr) {
File rootFile = null;
String folderPath = null;
try {
// 遍歷傳遞進來的數(shù)據(jù),然后根據(jù)傳入的數(shù)據(jù)進行創(chuàng)建文件夾
for (SelectTreeMoneyModel selectTreeMoneyModel : data.getResult()) {
// 創(chuàng)建一個file實例對象,指向文件路徑(存放照片的根目錄)
zipFileStr = folderUri + selectTreeMoneyModel.getTitle();
folderPath = selectTreeMoneyModel.getTitle();
rootFile = new File(zipFileUri + selectTreeMoneyModel.getTitle());
if (!rootFile.exists()) {
// 創(chuàng)建新文件夾,可以多層(mkdir()創(chuàng)建新文件夾,只能創(chuàng)建一層)
rootFile.mkdirs();
}
// 根據(jù)判斷遞歸的創(chuàng)建文件夾,如果是false則有子集
if (!selectTreeMoneyModel.isLeaf()) {
mkdirsChild(selectTreeMoneyModel.getChildren(), rootFile);
}
}
// 創(chuàng)建文件輸出流(zip流對象)【實際創(chuàng)建了zip文件,0kb】
FileOutputStream fos1 = new FileOutputStream(new File(zipFileStr + ".zip"));
// 壓縮法
toZip1(rootFile, fos1, true);
//TODO 刪除文件和壓縮文件,要保證每次壓縮只保存一份最新的存在。 因為是刪除文件,所以要慎用
//delFolder(folderUri + folderPath);
//delFolder(zipFileStr);
} catch (IOException e) {
e.printStackTrace();
}
// 拼接返回的壓縮包地址
String urlResult = url + folderPath + ".zip";
return urlResult;
}
/**
* 刪除文件夾
*
* @param folderPath 文件夾完整絕對路徑
*/
public static void delFolder(String folderPath) {
try {
// 刪除目錄下所有內(nèi)容
delAllFile(folderPath);
File myFilePath = new File(folderPath);
//刪除空文件夾
myFilePath.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 刪除指定文件夾下所有文件
*
* @param path 文件夾完整絕對路徑
*/
public static boolean delAllFile(String path) {
boolean bea = false;
File file = new File(path);
if (!file.exists()) {
return bea;
}
if (!file.isDirectory()) {
return bea;
}
//
String[] tempList = file.list();
File temp;
if (tempList != null) {
for (String var : tempList) {
// separator 代替文件或文件夾路徑的斜線或反斜線,防止跨平臺出現(xiàn)錯誤
if (path.endsWith(File.separator)) {
temp = new File(path + var);
} else {
temp = new File(path + File.separator + var);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
//先刪除文件夾里面的文件
delAllFile(path + "/" + var);
//再刪除空文件夾
delFolder(path + "/" + var);
bea = true;
}
}
}
return bea;
}
/**
* 壓縮的遞歸方法
*
* @param sourceFile 源文件
* @param zos zip輸出流
* @param fileName 源文件的名稱
* @param keepDirStructure 是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu);
* false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會出現(xiàn)同名文件,會壓縮失敗)
*/
private void compress(File sourceFile, ZipOutputStream zos, String fileName, boolean keepDirStructure) throws IOException {
byte[] buf = new byte[2 * 1024];
// 判斷是否是一個文件
if (sourceFile.isFile()) {
// 向zip輸出流中添加一個zip實體,構(gòu)造器中name為zip實體的文件的名字
zos.putNextEntry(new ZipEntry(fileName));
// 創(chuàng)建文件(即某張圖片)的輸入流
try (FileInputStream in = new FileInputStream(sourceFile)) {
int len;
// read方法:每調(diào)用一次就從FileInputStream流中讀取一個字節(jié),并返回下一個數(shù)據(jù)字節(jié),若已到達末尾,就返回-1。
while ((len = in.read(buf, 0, buf.length)) != -1) {
zos.write(buf, 0, len);
}
// 實際寫入到了zip輸出流的zip實體中,還沒寫到文件中【zip文件時0kb,不能打開,因為流沒有關(guān)閉】
zos.closeEntry();
} catch (IOException e) {
throw new IOException(e);
}
} else {
// 源文件時目錄
// 獲取該目錄下所有文件和目錄的絕對路徑
File[] listFiles = sourceFile.listFiles();
// 空目錄
if (listFiles == null || listFiles.length == 0) {
// 需要保留原來的文件結(jié)構(gòu)時,需要對空文件夾進行處理
if (keepDirStructure) {
// 空文件夾的處理
zos.putNextEntry(new ZipEntry(fileName + "/"));
// 沒有文件,不需要文件的copy
zos.closeEntry();
}
} else {
// 非空目錄
for (File file : listFiles) {
if (keepDirStructure) {
// 注意:getName()僅得到最后一層的名字,不是路徑,所以要加“/”,不然所有文件都跑到壓縮包根目錄下了
compress(file, zos, fileName + "/" + file.getName(), true);
} else {
compress(file, zos, file.getName(), false);
}
}
}
}
}
/**
* 壓縮成ZIP 方法1:保留多級目錄結(jié)構(gòu)
*
* @param sourceFile 照片存放路徑
* @param out 壓縮文件輸出流
* @param keepDirStructure 是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu);
* false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會出現(xiàn)同名文件,會壓縮失敗)
*/
public void toZip1(File sourceFile, OutputStream out, boolean keepDirStructure) throws IOException {
long start = System.currentTimeMillis();
// 創(chuàng)建壓縮輸出流,java7的新語法:Try-with-resources,會確保異常拋出或者try代碼塊結(jié)束時close流【該流必須實現(xiàn)AutoCloseable類】(若是java7之前的版本,則不會生效)
try (ZipOutputStream zos = new ZipOutputStream(out)) {
// 壓縮
compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
long end = System.currentTimeMillis();
System.out.println("壓縮完成,耗時:" + (end - start) + " ms");
} catch (IOException e) {
throw new IOException(e);
}
}
最后的實現(xiàn)結(jié)果
文章來源:http://www.zghlxwxcb.cn/news/detail-814434.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-814434.html
總結(jié): 主要還是要理清楚你的層級關(guān)系,
1.然后在遞歸的時候一定要遞歸到最底層,然后根據(jù)最底層的數(shù)據(jù)查找跟附件表有關(guān)系的ID進行查找,然后將有關(guān)系的文件下載到指定的文件夾下,
2.然后打包成為壓縮包這種實現(xiàn)直接可以進行百度查找到適合自己的工具類,如果不是直接適用,可以進行修改工具類的方法進行適配。
到了這里,關(guān)于SpringBoot根據(jù)多階層創(chuàng)建文件,然后壓縮成壓縮包進行下載的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!