臨時接到一個需求說讓根據按照下麵的這個圖片的結構來打包下載指定位置下的文件到指定位置! 實現思路: 1.把已經實現的樹形結構的代碼進行調用,拿到他的數據進行創建對應的文件夾 2.因為結構下方的文件沒有特別直觀的資料庫中的關聯關係,所以還需要對於管理關係進行梳理 3.創建好階級文件,然後調用網上找的工 ...
臨時接到一個需求說讓根據按照下麵的這個圖片的結構來打包下載指定位置下的文件到指定位置!
實現思路:
1.把已經實現的樹形結構的代碼進行調用,拿到他的數據進行創建對應的文件夾
2.因為結構下方的文件沒有特別直觀的資料庫中的關聯關係,所以還需要對於管理關係進行梳理
3.創建好階級文件,然後調用網上找的工具類打包成為rar壓縮包,然後把路勁交給前端進行調用下載
調用數據,然後傳遞給創建文件方法進行實現:
/**
* 打包佐證成果文件,壓縮成為壓縮包!
*
* @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) {
// 獲取樹形結構
Result<List<SelectTreeMoneyModel>> loadAllTreeRoot = this.loadAllTreeRoot(projectId, departId);
// 下載壓縮文件,將獲取到的樹形結構,傳遞到實現類進行解析跟實現
String downloadZipFile = downloadZipFile(loadAllTreeRoot, "佐證跟成果", "/");
return Result.ok(downloadZipFile);
}
遞歸的創建子集文件夾,然後調用工具類進行壓縮成為壓縮包文件,註:刪除文件必須捋清楚然後進行使用,其實不刪除也只會在指定的位置生成一份,所以我這邊沒有進行使用!
/**
* 遞歸的創建子集文件夾
*
* @param data
* @param rootFile
*/
private void mkdirsChild(List<SelectTreeMoneyModel> data, File rootFile) {
for (SelectTreeMoneyModel datum : data) {
// 創建一個file實例對象,指向文件路徑(存放照片的根目錄)
File childs = new File(rootFile, datum.getTitle());
if (!childs.exists()) {
childs.mkdirs();
}
// 判斷如果下麵還有子節點,如果有則調用自身
if (!datum.isLeaf()) {
mkdirsChild(datum.getChildren(), childs);
}
// 如果下麵沒有子節點,則進行判斷下麵是否有附件,如果有附件則進行下載到指定的文件夾內。
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) {
// 判斷附件表不是空的,則進行下載文件到對應的文件夾下
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 數據集合【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 {
// 遍歷傳遞進來的數據,然後根據傳入的數據進行創建文件夾
for (SelectTreeMoneyModel selectTreeMoneyModel : data.getResult()) {
// 創建一個file實例對象,指向文件路徑(存放照片的根目錄)
zipFileStr = folderUri + selectTreeMoneyModel.getTitle();
folderPath = selectTreeMoneyModel.getTitle();
rootFile = new File(zipFileUri + selectTreeMoneyModel.getTitle());
if (!rootFile.exists()) {
// 創建新文件夾,可以多層(mkdir()創建新文件夾,只能創建一層)
rootFile.mkdirs();
}
// 根據判斷遞歸的創建文件夾,如果是false則有子集
if (!selectTreeMoneyModel.isLeaf()) {
mkdirsChild(selectTreeMoneyModel.getChildren(), rootFile);
}
}
// 創建文件輸出流(zip流對象)【實際創建了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 {
// 刪除目錄下所有內容
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 代替文件或文件夾路徑的斜線或反斜線,防止跨平臺出現錯誤
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 是否保留原來的目錄結構,true:保留目錄結構;
* false:所有文件跑到壓縮包根目錄下(註意:不保留目錄結構可能會出現同名文件,會壓縮失敗)
*/
private void compress(File sourceFile, ZipOutputStream zos, String fileName, boolean keepDirStructure) throws IOException {
byte[] buf = new byte[2 * 1024];
// 判斷是否是一個文件
if (sourceFile.isFile()) {
// 向zip輸出流中添加一個zip實體,構造器中name為zip實體的文件的名字
zos.putNextEntry(new ZipEntry(fileName));
// 創建文件(即某張圖片)的輸入流
try (FileInputStream in = new FileInputStream(sourceFile)) {
int len;
// read方法:每調用一次就從FileInputStream流中讀取一個位元組,並返回下一個數據位元組,若已到達末尾,就返回-1。
while ((len = in.read(buf, 0, buf.length)) != -1) {
zos.write(buf, 0, len);
}
// 實際寫入到了zip輸出流的zip實體中,還沒寫到文件中【zip文件時0kb,不能打開,因為流沒有關閉】
zos.closeEntry();
} catch (IOException e) {
throw new IOException(e);
}
} else {
// 源文件時目錄
// 獲取該目錄下所有文件和目錄的絕對路徑
File[] listFiles = sourceFile.listFiles();
// 空目錄
if (listFiles == null || listFiles.length == 0) {
// 需要保留原來的文件結構時,需要對空文件夾進行處理
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:保留多級目錄結構
*
* @param sourceFile 照片存放路徑
* @param out 壓縮文件輸出流
* @param keepDirStructure 是否保留原來的目錄結構,true:保留目錄結構;
* false:所有文件跑到壓縮包根目錄下(註意:不保留目錄結構可能會出現同名文件,會壓縮失敗)
*/
public void toZip1(File sourceFile, OutputStream out, boolean keepDirStructure) throws IOException {
long start = System.currentTimeMillis();
// 創建壓縮輸出流,java7的新語法:Try-with-resources,會確保異常拋出或者try代碼塊結束時close流【該流必須實現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);
}
}
最後的實現結果
總結: 主要還是要理清楚你的層級關係,
1.然後在遞歸的時候一定要遞歸到最底層,然後根據最底層的數據查找跟附件表有關係的ID進行查找,然後將有關係的文件下載到指定的文件夾下,
2.然後打包成為壓縮包這種實現直接可以進行百度查找到適合自己的工具類,如果不是直接適用,可以進行修改工具類的方法進行適配。