使用apache poi解析Excel加水印时报错Zip Bomb

问题描述:

使用apache poi包对存在的excel文件添加水印操作,当excel数据量小的时候没啥问题,数据量大了就会报错Zip Bomb,具体报错如下:

java.io.IOException: Zip bomb detected! 
The file would exceed the max. ratio of compressed file size to the size of the expanded data. 
This may indicate that the file is used to inflate memory usage and thus could pose a security risk.
You can adjust this limit via ZipSecureFile.setMinInflateRatio() if you need to work with files which exceed this limit. 
Uncompressed size: 105682, Raw/compressed size: 651, ratio: 0.006160 
Limits: MIN_INFLATE_RATIO: 0.010000, Entry: xl/styles.xml 
org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream.checkThreshold(ZipArchiveThresholdInputStream.java:132)
org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream.read(ZipArchiveThresholdInputStream.java:82)
org.apache.poi.util.IOUtils.toByteArray(IOUtils.java:182)
org.apache.poi.util.IOUtils.toByteArray(IOUtils.java:149)
org.apache.poi.util.IOUtils.toByteArray(IOUtils.java:136) org.apache.poi.openxml4j.util.ZipArchiveFakeEntry.<init>(ZipArchiveFakeEntry.java:47)
org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource.<init>(ZipInputStreamZipEntrySource.java:53)
org.apache.poi.openxml4j.opc.ZipPackage.<init>(ZipPackage.java:106)
org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:307)
org.apache.poi.ooxml.util.PackageHelper.open(PackageHelper.java:47)
org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:309)

问题原因:

这个异常 java.io.IOException: Zip bomb detected! 是由 Apache POI 库抛出的,用于处理 Excel 文件(如 XLSX 格式)。Apache POI 有一个安全特性,用于检测和处理潜在的 "zip bomb" 攻击。Zip bomb 是一种恶意压缩文件,它可以在解压时产生异常大量的数据,从而耗尽系统资源。

xlsx在本质上还是一个zip文件,excel文件在压缩后的大小与解压后的大小之间的比率太低(只有 0.006160),低于 Apache POI 设定的最小比率限制(默认是 0.01,即 1%)。这触发了异常,因为 Apache POI 认为该文件不安全,会消耗大量内存有导致内存耗尽的风险。

解决方案:

首先你要确认你的excel文件是没问题的,安全的文件,然后你就可以手动调整压缩率,低于报错的这个比率即可。

关键代码:ZipSecureFile.setMinInflateRatio(0.005);

public static void main(String[] args) {  
        // 设置最小压缩比率,例如 0.005(即 0.5%)  
        ZipSecureFile.setMinInflateRatio(0.005);  
  
        try (FileInputStream fis = new FileInputStream(new File("path/to/your/file.xlsx")))         
        {  
            // 创建 Workbook 对象(这里使用 XSSFWorkbook 来处理 XLSX 文件)  
            Workbook workbook = new XSSFWorkbook(fis);  
  
            // 接下来你可以使用 workbook 对象来读取和处理 Excel 文件  
            // ...  
  
            // 关闭 workbook(在 try-with-resources 语句中会自动关闭)  
        } catch (IOException e) {  
            // 处理异常  
            e.printStackTrace();  
        }  
}  
  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用Apache POIExcel单元格转换为图片需要以下步骤: 1. Excel文件并创建工作簿对象: ``` File file = new File("path/to/excel/file.xlsx"); Workbook workbook = WorkbookFactory.create(file); ``` 2. 获取要转换为图片的单元格对象: ``` Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表 Row row = sheet.getRow(0); // 获取第一行 Cell cell = row.getCell(0); // 获取第一个单元格 ``` 3. 创建绘图对象并设置绘图区域: ``` Drawing drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, cell.getColumnIndex(), row.getRowNum(), cell.getColumnIndex() + 1, row.getRowNum() + 1); ``` 4. 创建图片对象并将其插入绘图对象: ``` byte[] imageBytes = // 从单元格中获取图片字节数组 int pictureIndex = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_JPEG); Picture picture = drawing.createPicture(anchor, pictureIndex); ``` 5. 将工作簿写入输出流: ``` FileOutputStream out = new FileOutputStream("path/to/output/image.jpg"); workbook.write(out); out.close(); ``` 完整代码示例: ``` File file = new File("path/to/excel/file.xlsx"); Workbook workbook = WorkbookFactory.create(file); Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表 Row row = sheet.getRow(0); // 获取第一行 Cell cell = row.getCell(0); // 获取第一个单元格 Drawing drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, cell.getColumnIndex(), row.getRowNum(), cell.getColumnIndex() + 1, row.getRowNum() + 1); byte[] imageBytes = // 从单元格中获取图片字节数组 int pictureIndex = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_JPEG); Picture picture = drawing.createPicture(anchor, pictureIndex); FileOutputStream out = new FileOutputStream("path/to/output/image.jpg"); workbook.write(out); out.close(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值