java zip 压缩工具类




java zip 压缩工具类


目录结构

  • 环境依赖
  • zip压缩工具类
  • 遇到的问题










环境依赖


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starterartifactId>
    <version>2.3.2.RELEASEversion>
dependency>

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.75version>
    <scope>compilescope>
dependency>










工具类

import com.alibaba.fastjson.JSONObject;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 压缩文件工具。
 * 不生成中间过渡文件,直接操作压缩包。
 * 仅支持一层文件【非文件夹,非压缩包】操作。
 * 
 * 注意:
 * 不适用于【高并发场景】。
 *
 * @author zhangsan coder
 * @since 2022-09-4 14:52
 **/
public class ZipUtil {


    /**
     * 压缩 zip 到 outputStream 位置。
     * 压缩 zip 文件。
     * 

* 注意:inputStreamList 与 zipFileNames 长度必须一一对应,文件数据与名称一对一的对应关系。 *

* 如:

* inputStreamList[0] -> zipFileNames[0]。

* inputStreamList[1] -> zipFileNames[1]。

* inputStreamList[2] -> zipFileNames[2]。

* * @param inputStreamList 被压缩的列表数据。【String形式】 * @param zipFileNames zip 中的每个文件的名称。【长度必须严格与 inputStreamList 同长度】 * @param outputStream 压缩包输出位置。 */ public static void toZip(List<InputStream> inputStreamList, List<String> zipFileNames, OutputStream outputStream) throws IOException { if (inputStreamList.size() <= 0) { return; } if (zipFileNames.size() <= 0) { return; } // 设置压缩流:直接写入response,实现边压缩边下载 ZipOutputStream zipos = null; try { zipos = new ZipOutputStream(new BufferedOutputStream(outputStream)); zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法 } catch (Exception e) { return; } // 循环将文件写入压缩流 DataOutputStream os = null; for (int i = 0; i < inputStreamList.size(); i++) { zipos.putNextEntry(new ZipEntry(StringUtils.isEmpty(zipFileNames.get(i)) ? "解压的数据" + i : zipFileNames.get(i))); os = new DataOutputStream(zipos); byte[] b = new byte[4 * 1024]; int length = 0; while ((length = inputStreamList.get(i).read(b)) != -1) { os.write(b, 0, length); } inputStreamList.get(i).close(); zipos.closeEntry(); } // 关闭流 try { if (os != null) { os.flush(); os.close(); } zipos.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 解压 zip 并 获取解压后的数据。【单个 zip】 * 注意: * 得确保 zip 文件中的数据为 JSON 数据; * 且 JSON 数据必须与 toClass 属性字段保持一致! * 属性取值范围只能在 toClass 属性名内,超过范围则报错! * 仅支持一层解压。 *

* 如: * 有字段:a、b、c、d。 * 转换成功:a、b。 a、b、c。 a、c。 a、b、c、d。 * 转换失败:a、e。 a、b、f。 * * @param zipInputStream 压缩流。 * @param toClass 转换的类型。 * @return 解压后的文件数据。 */ // @SneakyThrows public static <T> List<T> unZipForJsonToList(ZipInputStream zipInputStream, Class<T> toClass) throws IOException, NullPointerException { if (toClass == null) { throw new NullPointerException("提取的对象不能为空!"); } if (zipInputStream == null) { throw new NullPointerException("压缩流不能为空!"); } List<T> list = new ArrayList<>(); Map<String, String> zipFile = getZipFile(zipInputStream); //map 的entry遍历方法 for (Map.Entry<String, String> en : zipFile.entrySet()) { // System.out.println(en.getKey() + " ==》 " + en.getValue()); T t = JSONObject.parseObject(en.getValue(), toClass); list.add(t); } if (list.size() <= 0) { throw new NullPointerException("zip 提取数据失败!"); } return list; } /** * 解压 zip 并 获取解压后的数据。【单个 zip】 * 注意: * 得确保 zip 文件中的数据为 JSON 数据; * 且 JSON 数据必须与 toClass 属性字段保持一致! * 属性取值范围只能在 toClass 属性名内,超过范围则报错! * 仅支持一层解压。 *

* 如: * 有字段:a、b、c、d。 * 转换成功:a、b。 a、b、c。 a、c。 a、b、c、d。 * 转换失败:a、e。 a、b、f。 * * @param zipInputStream 压缩流。 * @param toClass 转换的类型。 * @return 解压后的文件数据。 */ // @SneakyThrows public static <T> Map<String, T> unZipForJsonToMap(ZipInputStream zipInputStream, Class<T> toClass) throws IOException, NullPointerException { if (toClass == null) { throw new NullPointerException("提取的对象不能为空!"); } if (zipInputStream == null) { throw new NullPointerException("压缩流不能为空!"); } Map<String, String> zipFile = getZipFile(zipInputStream); Map<String, T> returnMap = new ConcurrentHashMap<>(); //map 的entry遍历方法 for (Map.Entry<String, String> en : zipFile.entrySet()) { // System.out.println(en.getKey() + " ==》 " + en.getValue()); T t = JSONObject.parseObject(en.getValue(), toClass); returnMap.put(en.getKey(), t); } if (returnMap.size() <= 0) { throw new NullPointerException("zip 提取数据失败!"); } return returnMap; } /** * 根据入参,返回提取到的文件字符串形式数据。 * * @param srcZip 源zip。 * @return 返回提取到的文件数据内容【字符串形式】,若没有获取到内容,则返回 null 。 * @throws IOException */ public static Map<String, String> getZipFile(ZipInputStream srcZip) throws IOException { //读取一个目录 ZipEntry nextEntry = null; // 压缩包内的文件数据【字符串形式】。 Map<String, String> stringMap = new ConcurrentHashMap<>(); StringBuilder jsonString = new StringBuilder(); //不为空,则进入循环。 while ((nextEntry = srcZip.getNextEntry()) != null) { String name = nextEntry.getName(); // System.out.println("name = " + name); // for (String fileName : fileNames) { // if (!StringUtils.isEmpty(name) && name.equalsIgnoreCase(fileName)) { // System.out.println("压缩包中存在当前文件名:" + fileName); // System.out.println(); // 提取文件数据。 try ( ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream) ) { int n; byte[] bytes = new byte[4 * 1024]; // byte[] bytes = new byte[1]; while ((n = srcZip.read(bytes)) != -1) { bufferedOutputStream.write(bytes, 0, n); // 获取文件数据。 jsonString.append(new String(bytes, 0, n)); // System.out.print(jsonString); } stringMap.put(name, jsonString.toString()); jsonString = new StringBuilder(); } catch (IOException e) { e.printStackTrace(); } finally { //关闭当前文件。 srcZip.closeEntry(); } // System.out.println(); // System.out.println("================================================================================"); // System.out.println(); } return stringMap; } // public static void main(String[] args) throws IOException { private static void main(String[] args) throws IOException { // List routes = unZipForJson( // new ZipInputStream(new FileInputStream(new File("C:\\\\Users\\\\zhangsan\\\\Desktop\\\\测速.zip"))) // , Route.class // ); // System.out.println("============================ 转换的对象列表 =========================="); // routes.forEach(System.out::println); // System.out.println("==================================================================="); } }










遇到的问题



异常:org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe。

原因:传输流其中一端突然断开关闭导致的。

  • 针对于 File ,就是文件传输过程中,物理断开连接。
  • 针对于 socket 断网,网络超时导致的请求断开等等。

注: 在Java中,没有具体的BrokenPipeException。 将此类错误包含在另一个异常,例如java.io.IOException:Broken pipe


问题分析:

  1. 报文过大:处理的报文过大,导致客户的端无法解析报文。
  2. 文件过大:处理时间过长,由于执行时间较长或频率较高,程序或服务器出发超时直接结束进程。
  3. 重复提交:处理时间过长导致当客户端重复发送请求,而上次请求尚未完成,下次请求会close上次请求。
  4. 数据库配置问题:mysql配置文件忘记配置wait_timeout参数,导致数据库连接顺序关闭(RS、PS、CONN)。
  5. 另外就是:Java虚拟机内存太小或者使用低版本的JVM,出发垃圾回收。

参考文献
地址:参考文件

你可能感兴趣的:(java,工具类,zip)