Java实现压缩解压文件2.0版本

本文是对前面写的《Java实现压缩解压文件》进行了问题修复与功能补充。


问题修复:

老版本在实现上面有些问题,在通过addFile像压缩包中添加文件时,一旦前面的addFile添加文件失败,就会导致接下来所有的addFile都无法成功。原先的方法实现为:

public ZipObject addFile(byte[] fileBytes, String fileName) {
            try {
                // 可以理解一个ZipEntry就表示压缩包里面的一个文件
                ZipEntry zipEntry = new ZipEntry(fileName);
                zos.putNextEntry(zipEntry);
                zos.write(fileBytes, 0, fileBytes.length);
            } catch (IOException e) {
                e.printStackTrace();
                if (bos!=null) {
                    try {
                        bos.close();
                    } catch (IOException ee){}
                }
                if (zos!=null) {
                    try {
                        zos.close();
                    } catch (IOException ee){}
                }
            }
            return this;
        }

上述原因是因为在异常捕获catch代码块中的bos.close()与zos.close()将文件流关闭了,这样在后续继续调用addFile时就会出现报错了。因此,不需要关闭文件流。改造后的方法为:

public ZipObject addFile(byte[] fileBytes, String fileName) {
            try {
                // 可以理解一个ZipEntry就表示压缩包里面的一个文件
                ZipEntry zipEntry = new ZipEntry(fileName);
                zos.putNextEntry(zipEntry);
                zos.write(fileBytes, 0, fileBytes.length);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return this;
        }

功能补充:

(1)在实际使用中,我们经常遇到的文件有很多是Excel,Word文档等。比如会使用org.apache.poi.ss.usermodel.Workbook来生成Excel文件。当与Workbook结合我们的ZipUtil如何来使用呢,代码如下:(因为addFile只提供了一个byte[]类型的参数,因此我们需要先将Workbook内容写到ByteArrayOutputStream,再通过ByteArrayOutputStream获取字节数组)

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
workbook.write(byteArrayOutputStream);
zipObject.addFile(byteArrayOutputStream.toByteArray(), "示例.xls");

为了简化该操作,我们重载一个方法:

public ZipObject addFile(ByteArrayOutputStream outputStream, String fileName) {
            return addFile(outputStream.toByteArray(), fileName);
        }

(2)在实际使用中,我们经常需要将压缩包文件响应给浏览器进行下载。比如结合HttpServletResponse将内容响应给浏览器。代码如下:

OutputStream outputStream = response.getOutputStream();
response.setHeader("Content-Disposition", "attachment;filename=file.zip");
response.setContentType("application/octet-stream;charset=UTF-8");
outputStream.write(zipObject.create());

为了简化该操作,我们重载一个方法:

public void write(OutputStream outputStream) {
            try {
                outputStream.write(create());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

更可以用参数将HttpServletResponse接受,将响应浏览器功能的代码封装到方法中。

附上改造之后完整的代码:

public class ZipUtil {
    private ZipUtil() {
        throw new RuntimeException("Illegal operation");
    }

    // 压缩文件
    public static ZipObject createZipObject() {
        return new ZipObject();
    }

    // 解压文件,参数是压缩文件字节数组
    public static UnZipObject createUnZipObject(byte[] bytes) {
        if (bytes==null || bytes.length==0) {
            throw new IllegalArgumentException("bytes is null");
        }

        return new UnZipObject(bytes);
    }

    public static class ZipObject {
        // 工具流
        private ZipOutputStream zos;
        // 使用带有缓冲功能的文件流存储文件
        private ByteArrayOutputStream bos;

        private ZipObject() {
            bos = new ByteArrayOutputStream();
            // 文件数据流实际存储在了bos
            zos = new ZipOutputStream(bos);
        }

        /**
         * 添加一个文件到压缩包中
         * @param fileBytes  文件的字节数组
         * @param fileName 文件名,带文件类型的,比如:hello.xlsx
         * @return
         */
        public ZipObject addFile(byte[] fileBytes, String fileName) {
            try {
                // 可以理解一个ZipEntry就表示压缩包里面的一个文件
                ZipEntry zipEntry = new ZipEntry(fileName);
                zos.putNextEntry(zipEntry);
                zos.write(fileBytes, 0, fileBytes.length);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return this;
        }

        /**
         * 结合文件流,比如 Workbook.write();
         * @param outputStream
         * @param fileName
         * @return
         */
        public ZipObject addFile(ByteArrayOutputStream outputStream, String fileName) {
            return addFile(outputStream.toByteArray(), fileName);
        }

        /**
         * 生成压缩包的字节数组
         * @return
         */
        public byte[] create() {
            byte[] bytes = null;
            try {
                // 将数据写到ByteArrayOutputStream中
                zos.finish();
                bytes = bos.toByteArray();
                bos.flush();
                zos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (bos!=null) {
                    try {
                        bos.close();
                    } catch (IOException e){}
                }
                if (zos!=null) {
                    try {
                        zos.close();
                    } catch (IOException e){}
                }
            }

            return bytes;
        }

        /**
         * 结合Spring框架的HttpServletResponse response响应出去
         * zipObject.write(response.getOutputStream());
         * @param outputStream
         */
        public void write(OutputStream outputStream) {
            try {
                outputStream.write(create());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }


    public static class UnZipObject {
        // 工具流
        private ZipInputStream zis;
        // 使用带有缓冲功能的文件流存储文件
        private ByteArrayInputStream bis;

        private int size;

        private UnZipObject(byte[] bytes) {
            size = bytes.length;
            bis = new ByteArrayInputStream(bytes);
            // 文件数据流实际存储在了bos
            zis = new ZipInputStream(bis);
        }

        /**
         * 获取压缩包里面的文件,一个ZipEntry表示一个文件
         * @return
         */
        public List getEntrys() {
            List list = new ArrayList<>();
            try {
                ZipEntry nextEntry = zis.getNextEntry();
                // 一个个循环读取压缩文件中的内容,放进bytes数组中
                while (nextEntry!=null) {
                    byte[] bytes = new byte[size];
                    zis.read(bytes);
                    nextEntry.setExtra(bytes);
                    list.add(nextEntry);
                    nextEntry = zis.getNextEntry();
                }
            } catch (IOException e) {
                e.printStackTrace();
                if (bis!=null) {
                    try {
                        bis.close();
                    } catch (IOException ee){}
                }
                if (zis!=null) {
                    try {
                        zis.close();
                    } catch (IOException ee){}
                }
            }
            return list;
        }

    }

}

你可能感兴趣的:(博客,java,开发语言)