关于ZipOutputStream和GZIPOutputStream的区别及优缺点

ZipOutputStream:

  • 使用 ZipOutputStream 创建了一个 ZIP 归档文件,这在需要将多个文件打包成一个文件时非常有用。
  • 同样通过流式处理读取和写入数据,避免了内存溢出的问题。                                                  

GZIPOutputStream :

  • 使用 GZIPOutputStream 直接对文件内容进行 GZIP 压缩,这是一种高效的压缩方式,适用于大多数需要减少数据大小以节省存储或传输时间的场景。
  • 通过流式处理读取和写入数据,避免了将整个文件内容一次性加载到内存中,减少了内存使用的风险。

在实际开发中 GZIPOutputStream就已经足够用了,如果你的目的仅仅是压缩单个文件而不是创建 ZIP 归档,那么使用 ZipOutputStream 可能比 GZIPOutputStream 更复杂且效率稍低。

在实际开发中根据我们的业务需求不同我们的选择也不同

  • 如果只是压缩单个文件: GZIPOutputStream更优,因为它直接使用 GZIPOutputStream 进行压缩,这是为单个文件压缩设计的,且效率更高。
  • 如果是压缩多个文件:ZipOutputStream更优,但相应的也比GZIPOutputStream存在更多的编程困难

附上相应代码:

//ZipOutputStream 
@PostMapping  
public Result upload(@RequestParam("file") MultipartFile file) {  
    // 创建一个 ByteArrayOutputStream 来捕获 ZIP 输出的字节  
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  
      
    try (  
        // 创建一个 ZipOutputStream,用于将文件写入 ZIP 归档  
        // 这里,将其包装在 try-with-resources 语句中,以便自动关闭  
        ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)  
    ) {  
        // 创建一个 ZipEntry,它代表 ZIP 归档中的一个条目(即当前的file 文件)  
        ZipEntry zipEntry = new ZipEntry(file.getOriginalFilename());  
        // 将 ZipEntry 添加到 ZIP 归档中  
        zipOutputStream.putNextEntry(zipEntry);  
  
        try (BufferedInputStream bis = new BufferedInputStream(file.getInputStream())) {  
            // 创建一个缓冲区,用于读取和写入文件数据  
            byte[] buffer = new byte[1024];  
            int length;  
            // 从 MultipartFile 的 InputStream 读取数据,并将其写入 ZIP 归档  
            while ((length = bis.read(buffer)) > 0) {  
                zipOutputStream.write(buffer, 0, length);  
            }  
        }  
        // 关闭当前 ZIP 归档条目(即文件)  
        zipOutputStream.closeEntry();  
    } catch (IOException e) {  
        // 如果在 ZIP 处理过程中发生异常,则返回失败信息  
        return Result.fail("上传失败: " + e.getMessage());  
    }  
  
    // 获取 ZIP 归档的字节数据  
    byte[] zipBytes = byteArrayOutputStream.toByteArray();  
    // 将 ZIP 归档的字节数据插入到数据库中,数据库选择根据实际情况来定
    // 注意:通常,会将 ZIP 文件保存时带有 .zip 扩展名但这里我只是压缩一个文件 
    // 我选择直接保存原文件类型,可以从数据库中获取字节数组时,直接转化为对应的格式,但是这种方法只适用于压缩一个文件,或文件类型是相同时使用    
    fileService.insert(zipBytes, file.getOriginalFilename());  
    // 返回上传成功的消息  
    return Result.success("上传成功");  
}
//GZIPOutputStream 
@PostMapping  
public Result upload(@RequestParam("file") MultipartFile file) {  
    // 尝试资源自动关闭的代码块,包括 ByteArrayOutputStream、GZIPOutputStream 和 BufferedInputStream  
    try (  
        // 创建一个 ByteArrayOutputStream 来捕获 GZIP 输出的字节  
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
        // 创建一个 GZIPOutputStream,用于将文件内容压缩后写入 ByteArrayOutputStream  
        GZIPOutputStream gzipOut = new GZIPOutputStream(baos);  
        // 创建一个 BufferedInputStream 来包装 MultipartFile 的 InputStream,以提高读取效率  
        BufferedInputStream bis = new BufferedInputStream(file.getInputStream())  
    ) {  
  
        // 创建一个缓冲区,用于从 BufferedInputStream 读取数据并写入 GZIPOutputStream  
        byte[] buffer = new byte[1024];  
        int len; // 用于存储每次从 BufferedInputStream 读取的字节数  
  
        // 循环读取 BufferedInputStream 中的数据,直到没有更多数据可读  
        while ((len = bis.read(buffer)) > 0) {  
            // 将缓冲区中的数据写入 GZIPOutputStream 进行压缩  
            gzipOut.write(buffer, 0, len);  
        }  
  
        // 完成 GZIP 压缩过程,确保所有待压缩的数据都被处理  
        gzipOut.finish();  
  
        // 从 ByteArrayOutputStream 获取压缩后的字节数据  
        byte[] zip = baos.toByteArray();  
  
        // 将压缩后的字节数据和原始文件名(或带有压缩后缀的新文件名)保存到数据库中
        // 注意:通常,会在压缩文件添加一个特定的扩展名,如 ".gz",这里只是一个文件 
        fileService.insert(zip, file.getOriginalFilename());  
  
        // 返回上传成功的消息  
        return Result.success("上传成功");  
    } catch (IOException e) {  
        // 如果在文件读取、压缩或写入过程中发生 IOException,则返回上传失败的消息  
        return Result.fail("上传失败");  
    }  
}

附上我的数据库设计:

类型字段名
intid
longblobzip
varchar(255)         

fileName                        

这里之所以选择longblob来保存文件的字节数组,是因为在实际开发中所需压缩的文件大小都比较大而blob最大只能保存64KB的文件,但longblob最大可以保存4GB内存的文件。

这里附上blob相关类型的使用:

  1. Blob
    • 用于存储二进制大对象。
    • 长度根据存储引擎的不同而有所变化,但通常能够存储的数据量远超过标准文本类型(如VARCHAR或TEXT)。
    • 在MySQL中,Blob类型的最大长度可能会受到表行大小和存储引擎的限制。
    • 最大可存储64KB,即65,535字节。
  2. TinyBlob
    • 类似于Blob,但用于存储较小的二进制数据。
    • 最大长度通常比Blob小,适用于不需要存储大量二进制数据的场景。
    • 最大可存储255个字节
  3. MediumBlob
    • 介于Blob和LongBlob之间,提供了适中的存储能力。
    • 适用于存储中等大小的二进制数据,如中等大小的图片或音频文件。
    • 最大可存储16MB,即16,777,215字节
  4. LongBlob
    • 用于存储非常大的二进制数据。
    • 在MySQL中,LongBlob能够存储的最大数据量可以达到4GB(在MySQL 5.0.3及以后版本中),这对于存储大型文件如高清视频、大型图像集等非常有用。

使用LongBlob会遇到一个错误PacketTooBigException,这个问题的解决方法,这里我只说明MySql的解决方法,其他数据库遇到可以去查询解决办法

解决办法如下:

修改MySql的my.ini文件,通常在MySQL目录下,先剪切掉my.ini去到另一个目录因为MySQL是默认管理员修改的,直接修改my.ini是不可行的,在MySQL目录下新建一个my.ini,并去复制之前的my.ini粘贴到新的my.ini,在新的my.ini添加如下内容

[mysqld] 
max_allowed_packet=1073741824

 这里的1073741824是1GB,导致这个错误的原因就是因为MySql拒绝访问过大的文件,所以抛出这个错误,修改了这个之后就可以正常运行程序了

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值