java下载zip文件

一、使用工具

* java.utils 下的ZipOutputStream
* java.net 的http请求工具 HttpURLConnection

二、 zip下载

1. 通过浏览器以附件的形式下载到客户端 
      思路:
        response 的write方法要写出一个byte[],所以我们需要从ZipStreamOutputStream中获取到byte[]。 在java中从io流中获取byte的办法就是将
        io流写到字节数组输出流中ByteArrayOutputStream(即内存中)。 代码如下:
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ZipStreamOutputStream zos = new ZipStreamOutputStream(bos)
        // 向zos中写数据  ...
        byte[] data = bos.toByteArray();
      分析数据流流向如下: 
        图片字节数据byte[](jpg)  -->  ZipStreamOutputStream -->   ByteArrayOutputStream -> byte[](zip)
2. 下载到服务器文件目录下
      分析数据流流向如下:  
        图片字节数据byte[](jpg)  -->  ZipStreamOutputStream -->   FileOutputStream -> File(zip)

三、 注意点

1. 在向ZipOutputStream中写完数据后,必须马上关闭ZipOutputStream,否则zip文件会损坏
2. 对于包装流,关闭流的顺序问题
  一层套一层的包装流,关闭顺序一定是先关闭外层包装流,然后再关闭内层的流,否则会文件损坏,而且在关闭外层流的时候会报流已经关闭异常

四、 实践代码

` /**
 * 图像下载接口, 返回base64编码的图像信息
 *
 * @param response
 * @param imgType
 * @throws IOException
 */
@GetMapping("/getImage")
public void imageDownloadServer(HttpServletResponse response, String imgType) throws IOException {
    response.setContentType("text/plain");
    ServletOutputStream outputStream = response.getOutputStream();
    BASE64Encoder encoder = new BASE64Encoder();
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    File file = null;
    if ("F".equals(imgType)) {
        file = new File("C:\\Users\\cheva\\Desktop\\票样\\1.jpg");
    } else {
        file = new File("C:\\Users\\cheva\\Desktop\\票样\\2.jpg");
    }
    InputStream fis = new FileInputStream(file);
    int len = -1;
    byte[] buff = new byte[1024];
    while ((len = fis.read(buff)) != -1) {
        bos.write(buff, 0, len);
    }
    bos.flush();
    String base64 = encoder.encode(bos.toByteArray());
    fis.close();
    bos.close();
    outputStream.write(base64.getBytes(StandardCharsets.UTF_8));
    outputStream.flush();
    outputStream.close();
}


/**
 * 以附件的形式下载到客户端
 * @param request
 * @param response
 */
@GetMapping("/download")
public void dowload(HttpServletRequest request, HttpServletResponse response) {
    ByteArrayOutputStream bos = null;
    ZipOutputStream zipOutputStream = null;
    String outName = "my.zip";

    // 1. 向ZipOutputStream中写入数据。 流的走向: 数据字节 -> ZipOutputStream -> ByteArrayOutputStream
    // 注意: 在向ZipOutputStream中写完数据后,必须马上关闭ZipOutputStream,否则zip文件会损坏
    /**
     * 如下代码下载的zip文件会损坏
     * try {
     *             response.setContentType("application/zip");
     *             response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(outName, "UTF-8"));
     *             bos = new ByteArrayOutputStream();
     *             zipOutputStream = new ZipOutputStream(bos);
     *             packageZipStream("0011", zipOutputStream);
     *             outputStream = response.getOutputStream();
     *             outputStream.write(bos.toByteArray());
     *         } catch (Exception e) {
     *             e.printStackTrace();
     *         } finally {
     *             if (zipOutputStream != null) {
     *                 try {
     *                     zipOutputStream.close();
     *                 } catch (Exception e) {
     *                     System.out.println("流关闭异常");
     *                 }
     *             }
     *             if (bos != null) {
     *                 try {
     *                     bos.close();
     *                 } catch (Exception e) {
     *                     System.out.println("流关闭异常");
     *                 }
     *             }
     *         }
     *   原因在于在使用respose输出字节数组的时候,zipoutputstream还没有关闭,导致文件损坏,代码应该如下
     */

    try {
        bos = new ByteArrayOutputStream();
        zipOutputStream = new ZipOutputStream(bos);
        packageZipStream("0011", zipOutputStream);
    } catch (Exception e) {
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        try {
            ServletOutputStream os = response.getOutputStream();
            os.write(e.getMessage().getBytes());
            os.flush();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    } finally {
        // 注意: 像这种一层套一层的包装流,关闭顺序一定是先关闭外层包装流,然后再关闭内层的流,否则会文件损坏,而且在关闭外层流的时候会报流已经关闭异常
        if (zipOutputStream != null) {
            try {
                zipOutputStream.close();
            } catch (Exception e) {
                System.out.println("zip输出流关闭异常");
            }
        }
        if (bos != null) {
            try {
                bos.close();
            } catch (Exception e) {
                System.out.println("流关闭异常");
            }
        }
    }

    // 2. 响应数据
    try {
        response.setContentType("application/zip");
        response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(outName, "UTF-8"));
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(bos.toByteArray());
        outputStream.flush();
    } catch (Exception e) {
        e.printStackTrace();
    }
}


/**
 * 下载到服务器本地文件夹
 * @param response
 */
@GetMapping("/downloadLoc")
public void downloadLoc(HttpServletResponse response) {
    FileOutputStream fis = null;
    ZipOutputStream zipOutputStream = null;
    try {
        File file = new File("D:\\Compressed\\my.zip");

        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdir();
        }
        fis = new FileOutputStream(file);
        zipOutputStream = new ZipOutputStream(fis);
        packageZipStream("0011", zipOutputStream);
    } catch (Exception e) {
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        try {
            ServletOutputStream os = response.getOutputStream();
            os.write(e.getMessage().getBytes());
            os.flush();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    } finally {
        if (zipOutputStream != null) {
            try {
                zipOutputStream.close();
            } catch (Exception e) {
                System.out.println("流关闭异常");
            }
        }
        if (fis != null) {
            try {
                fis.close();
            } catch (Exception e) {
                System.out.println("流关闭异常");
            }
        }
    }
}


/**
 * 请求图片服务获取图像并写入到zip输出流中
 * @param imgId
 * @param zos
 */
private void packageZipStream(String imgId, ZipOutputStream zos) {
    String path = null;
    try {
        if (zos == null || imgId == null) {
            return;
        }
        // 1.  向zip输出流写入文件(ZipEntry), 如果有多个就循环下面五行代码。 注意: 如果文件重名,会ZipOutputStream会抛出ZipException
        path = imgId + File.separator + "正面.jpg";
        zos.putNextEntry(new ZipEntry(path));
        // 获取要写入ZipEntry的内容
        byte[] data = downloadImageFromURL("http://localhost:8098/chat-server/test/getImage?imgType=F");
        zos.write(data, 0, data.length);
        zos.closeEntry();

        path = imgId + File.separator + "反面.jpg";
        zos.putNextEntry(new ZipEntry(path));
        data = downloadImageFromURL("http://localhost:8098/chat-server/test/getImage?imgType=B");
        zos.write(data, 0, data.length);
        zos.closeEntry();
    } catch (Exception e) {
            if (e instanceof ZipException) {
                throw new RuntimeException(path + "重名,只进行一次下载处理");
            } else {
                throw new RuntimeException(e.getMessage());
            }

    }
}


/**
 * java HttpURLConnection作为客户端下载图像
 * @param urlPath
 * @return
 */
private byte[] downloadImageFromURL(String urlPath) {
    HttpURLConnection conn = null;
    InputStream is = null;
    byte[] data = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
        URL url = new URL(urlPath);
        conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(6000);
        conn.setDoInput(true);
        is = conn.getInputStream();
        if (conn.getResponseCode() == 200) {
            // 读取响应的输入流到字节输出流
            byte[] buff = new byte[1024];
            int len = -1;
            while ((len = is.read(buff)) != -1) {
                bos.write(buff, 0, len);
            }
            bos.flush();
            data = bos.toByteArray();
            BASE64Decoder decoder = new BASE64Decoder();
            data = decoder.decodeBuffer(new String(data));
        } else {
            data = null;
        }
    } catch (Exception e) {
            throw new RuntimeException("连接服务器异常");

    } finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (bos != null) {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return data;
}`
posted @   chevalyang  阅读(1276)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示