java 将附件打成压缩包

一.单个压缩包制作

package com.stream.core.util;
import com.alibaba.excel.util.CollectionUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * 打包下载
 * @author WYG
 *
 */
@Slf4j
public class ZipUtil {
	
	/**
	 * 将文件打成压缩包操作
	 * @param fileList
	 * @throws IOException
	 */
	public static void zipFile(List<File> fileList, String zipPath) {
		// 获取文件压缩包输出流
		try (
			OutputStream outputStream = new FileOutputStream(zipPath);
			CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream,new Adler32());
			ZipOutputStream zipOut = new ZipOutputStream(checkedOutputStream)){
			for (File file : fileList) {
				// 获取文件输入流
				InputStream fileIn = new FileInputStream(file);
				// 使用 common.io中的IOUtils获取文件字节数组
				byte[] bytes = IOUtils.toByteArray(fileIn);
				// 写入数据并刷新
				zipOut.putNextEntry(new ZipEntry(file.getName()));
				zipOut.write(bytes,0,bytes.length);
				zipOut.flush();
				fileIn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

二.多级压缩包:将附件打成压缩包后,再将多个压缩包进行压缩,压缩成大压缩包

package com.stream.invoice.task;
import com.stream.core.util.*;
import com.stream.invoice.bo.TEleCertXbrlPackageBO;
import com.stream.invoice.enums.InvoiceEleCertTypeEnums;
import com.stream.storage.bo.StorageUploadRspBO;
import com.stream.storage.handler.EcrStorageHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
public class EleCertXbrlPackageTask {
    @Autowired
    protected EcrStorageHandler ecrStorageHandler;  // 影像上传处理器
    /**
     * 压缩包执行
     *
     * @param yearMonth          年月
     * @param taxPayerNo         税号
     * @param eleCertXbrlDataMap xbrl文件数据通过唯一标识进行分组
     */
    private void downloadZipFile(String yearMonth, String taxPayerNo, List<File> fileList, Map<String, List<TEleCertXbrlPackageBO>> eleCertXbrlDataMap) {
        /** 一级压缩包 **/
        List<ZipUtil.ZipPo> list = new ArrayList<>();
        StringBuffer str = new StringBuffer();
        /** 将相同唯一标识的文件打包到同一个压缩包里 **/
        MapUtils.forEach(eleCertXbrlDataMap, (key, dataList) -> {
            /* 封装小压缩包(二级压缩包) */
            List<ZipUtil.ZipPo> zipPoList = new ArrayList<>();
            String zipName = "";
            /* 记录xbrl文件名称是否有相同的,如果有相同的,则在文件后面加上数字,依次递增  key:文件名  value:记录数字 */
            Map<String, Object> zipParaMap = new HashMap<>();
            for (TEleCertXbrlPackageBO certXbrlBO : dataList) {
                /* 获取票据类型 */
                if (StringUtil.isEmpty(zipName)) {
                    List<InvoiceEleCertTypeEnums> typeEnumsList = Arrays.stream(InvoiceEleCertTypeEnums.values()).filter(row -> certXbrlBO.getFileName().contains(row.getZipName())).collect(Collectors.toList());
                    zipName = typeEnumsList.get(0).getZipName();
                }
                if (StringUtil.isNotEmpty(certXbrlBO.getFileCode())) {
                    StorageUploadRspBO storageUploadRspBO = new StorageUploadRspBO();
                    try {
                        storageUploadRspBO = ecrStorageHandler.queryExample(certXbrlBO.getFileCode());
                        // 判断xbrl文件名称是否有相同的,如果有相同的,则在文件后面加上数字,依次递增
                        if (zipParaMap.containsKey(certXbrlBO.getFileName())) {
                            String suffix = certXbrlBO.getFileName().split("\\.")[certXbrlBO.getFileName().split("\\.").length - 1];
                            String name = certXbrlBO.getFileName().split("\\.")[certXbrlBO.getFileName().split("\\.").length - 2];
                            String num = zipParaMap.get(certXbrlBO.getFileName()).toString();
                            // 文件名称
                            String fileName = FileUtil.getResourcesPath() + File.separator + name + "(" + num + ")." + suffix;
                            File zipFile = FileUtil.downloadFilePath(fileName, storageUploadRspBO.getDownloadUrl());
                            fileList.add(zipFile); // 收集xbrl文件地址,方便后续删除
                            zipPoList.add(new ZipUtil.ZipPo(name + "(" + num + ")." + suffix, zipFile.getPath()));
                            zipParaMap.put(certXbrlBO.getFileName(), Integer.valueOf(num) + 1);
                        } else {
                            zipParaMap.put(certXbrlBO.getFileName(), 1);
                            File zipFile = FileUtil.downloadFilePath(certXbrlBO.getFileName(), storageUploadRspBO.getDownloadUrl());
                            fileList.add(zipFile); // 收集xbrl文件地址,方便后续删除
                            zipPoList.add(new ZipUtil.ZipPo(certXbrlBO.getFileName(), zipFile.getPath()));
                        }
                    } catch (Exception e) {
                        str.append("【" + certXbrlBO.getFileName() + "附件获取失败!: " + e.getMessage() + "】");
                    }
                }
            }
            zipName = zipName + "_receiver_" + DateUtils.getCurrentSimpDate() + "_" + key.split("\\.")[key.split("\\.").length - 2] + ".zip";
            list.add(new ZipUtil.ZipPo(zipName, zipPoList));  // 用唯一标识作为小压缩包名称
        });
        /* 记录压缩失败的数据如果有压缩失败的数据,则在压缩包里面添加 压缩包打包失败数据.txt 提示有文件可能没打上包*/
        String path = FileUtil.getResourcesPath() + "压缩包打包失败数据.txt";
        if (StringUtil.isNotEmpty(String.valueOf(str))) {
            try {
                File newTextFile = new File(path);
                FileWriter fileWriter = new FileWriter(newTextFile);
                fileWriter.write(String.valueOf(str));
                fileWriter.close();
                fileList.add(newTextFile); // 收集xbrl文件地址,方便后续删除
                list.add(new ZipUtil.ZipPo("压缩包打包失败数据.txt", newTextFile.getPath()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String yyyyMM = yearMonth.split("-")[0] + yearMonth.split("-")[1];
        String newZipName = "receiver_" + taxPayerNo + "_" + yyyyMM + ".zip";
        log.info("一级压缩包名称: " + newZipName);
        /** 判断压缩包是否存在,如果存在则删除 **/
        File zipNewFile = new File(FileUtil.getZipFilePath(newZipName));
        log.info("判断压缩包是否存在: " + zipNewFile.exists());
        if (zipNewFile.exists()) {
            zipNewFile.delete();
        }
        String base64 = ZipUtil.recursionExportZipToBase64(list);
        /** 上传到本地 **/
        File file = this.generateZip(base64, newZipName);
        log.info("file文件: " + file);
    }
    /**
     * 将base64转为file文件  压缩包专用
     *
     * @param base64
     * @param fileName
     * @return
     */
    public File generateZip(String base64, String fileName) {
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        File file = null;
        try {
            byte[] bytes = cn.hutool.core.codec.Base64.decode(base64);
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            bis = new BufferedInputStream(byteArrayInputStream);
            File zipFile = new File(FileUtil.DOWNLOAD_ZIP_FILE_PATH);
            log.info("创建资源zipFile:" + zipFile.getPath());
            if (!zipFile.exists()) {
                zipFile.mkdir();
            }
            String trueFilePath = FileUtil.getZipFilePath(fileName);
            file = new File(trueFilePath);
            File path = file.getParentFile();
            if (!path.exists()) {
                path.mkdir();
            }
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            byte[] buffer = new byte[1024];
            int length = bis.read(buffer);
            while (length != -1) {
                bos.write(buffer, 0, length);
                length = bis.read(buffer);
            }
            bos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                fos.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }
}

package com.stream.core.util;
import com.alibaba.excel.util.CollectionUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * 打包下载
 * @author WYG
 *
 */
@Slf4j
public class ZipUtil {
	@Data
	public static class ZipPo{
		/**
		 * 文件名/压缩包名
		 */
		private String name;
		/**
		 * 附件路径,为压缩包时该字段为null
		 */
		private String path;
		/**
		 * 递归的文件,当为文件时改字段为null
		 */
		private List<ZipPo> fileList;
		public ZipPo(String name, String path) {
			this.name = name;
			this.path = path;
		}
		public ZipPo(String name, List<ZipPo> fileList) {
			this.name = name;
			this.fileList = fileList;
		}
	}
	/**
	 * 将zip压缩包转为base64  大压缩包里面嵌套小压缩包
	 * @param fileList
	 */
	public static String recursionExportZipToBase64(List<ZipPo> fileList){
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		try (
			//把流输出到byteArrayOutputStream里面
			ZipOutputStream zos1=new ZipOutputStream(byteArrayOutputStream, StandardCharsets.UTF_8);
		){
			recursionPackage(zos1,fileList);
			zos1.close();
			return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
		}catch (Exception e){
			log.error("文件下载失败",e);
		}
		return null;
	}
	private static void recursionPackage(ZipOutputStream zos, List<ZipPo> fileList) {
		//先初始化一个,每次使用的时候reset,防止内存溢出
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		for (ZipPo zipPo : fileList) {
			zos.setMethod(ZipOutputStream.DEFLATED);
			try {
				zos.putNextEntry(new ZipEntry(zipPo.getName()));
			} catch (Exception e) {
				log.error(e.getMessage(),e);
			}
			//判断对象是附件还是压缩包
			if(CollectionUtils.isEmpty(zipPo.getFileList())){ //附件
				//获取附件并写到压缩包中
				log.info("文件名称:" + zipPo.getName() + "  文件地址:" + zipPo.getPath());
				if (StringUtil.isNotEmpty(zipPo.getPath())) {
					try (InputStream is = new FileInputStream(zipPo.getPath())){
						int b;
						byte[] buffer = new byte[1024];
						while ((b=is.read(buffer))!=-1){
							zos.write(buffer,0,b);
						}
						zos.flush();
					}catch (Exception e){
						log.error("文件输出异常",e);
					}
				}
			}else {//压缩包
				//重置一下内存流
				byteArrayOutputStream.reset();
				try (
					//把压缩包,往byteArrayOutputStream里面输出
					ZipOutputStream zos2=new ZipOutputStream(byteArrayOutputStream, StandardCharsets.UTF_8);
				){
					//递归压缩
					recursionPackage(zos2,zipPo.getFileList());
				}catch (Exception e){
					log.error("内部打包异常",e);
				}
				//把byteArrayOutputStream写到压缩包中,这个地方需要特别注意一下,不能把这两个写在上面的try里面,因为zos2关闭的时候会影响到zos,导致流的关闭顺序出错,压缩包文件被损坏,感谢评论区大佬的指正
				try {
					zos.write(byteArrayOutputStream.toByteArray());
					zos.flush();
				} catch (IOException e) {
					log.error("内部打包异常",e);
				}
			}
		}
	}
	/**
	 * 将文件打成压缩包操作
	 * @param fileList
	 * @throws IOException
	 */
	public static void zipFile(List<File> fileList, String zipPath) {
		// 获取文件压缩包输出流
		try (
			OutputStream outputStream = new FileOutputStream(zipPath);
			CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream,new Adler32());
			ZipOutputStream zipOut = new ZipOutputStream(checkedOutputStream)){
			for (File file : fileList) {
				// 获取文件输入流
				InputStream fileIn = new FileInputStream(file);
				// 使用 common.io中的IOUtils获取文件字节数组
				byte[] bytes = IOUtils.toByteArray(fileIn);
				// 写入数据并刷新
				zipOut.putNextEntry(new ZipEntry(file.getName()));
				zipOut.write(bytes,0,bytes.length);
				zipOut.flush();
				fileIn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

package com.stream.core.util;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
/**
 * 文件读取工具类
 */
@Slf4j
public class FileUtil {
    //系统文件分隔符
    public static final String SEPARATOR = File.separator;
    //文件下载路径这里是绝对路径,使用nas共享
    public static final String DOWNLOAD_FILE_PATH = "/CWGXLOCAL/downloadFile";
    //文件下载路径这里是绝对路径,使用nas共享
    public static final String DOWNLOAD_ZIP_FILE_PATH = "/CWGXLOCAL/downloadZipFile";
    /**
     * 得到资源路径
     *
     * @return {@link String}
     */
    public static String getResourcesPath() {
        return System.getProperty("user.dir") + "/storageFile/" + DateUtils.getCurrentSimpDate();
    }
    /**
     * 下载zip文件的全路径名
     *
     * @param fileName 文件名
     * @return {@link String}
     */
    public static String getZipFilePath(String fileName) {
        File zipFile = new File(FileUtil.DOWNLOAD_ZIP_FILE_PATH);
        log.info("创建资源zipFile:" + zipFile.getPath());
        log.info("创建资源!zipFile.exists():" + !zipFile.exists());
        if (!zipFile.exists()) {
            zipFile.mkdir();
        }
        return DOWNLOAD_ZIP_FILE_PATH + SEPARATOR + fileName;
    }
    /**
     * 从影像服务器获取下载地址 下载到本地nas
     * @param fileName  附件名称
     * @param downloadUrl 影像下载地址
     * @return
     * @throws IOException
     */
    public static File downloadFilePath(String fileName, String downloadUrl) {
        File file = null;
        try {
            URL url = new URL(downloadUrl);
            File newFile = new File(fileName);
            Path path = newFile.toPath();
            Files.copy(url.openStream(), path);
            file = path.toFile();
        }catch (Exception e){
            e.printStackTrace();
        }
        return file;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值