如何使用Apache POI逐单元格提取Excel图片并存储到文件夹?
如何用Apache POI逐单元格提取Excel中的图片并按单元格/行号存储?
我明白你想要的是按单元格/行号来区分提取的图片,而不是一股脑导出所有图片——原来的代码确实是一次性把所有图片都捞出来,没法关联到具体单元格。其实Apache POI里的图片对象是带有锚点信息的,通过这个锚点就能定位到它所在的单元格位置,咱们可以利用这一点来实现你的需求。
核心思路
每个HSSFPicture都绑定了一个HSSFClientAnchor(锚点),这个锚点记录了图片在工作表中占据的起始和结束单元格位置。我们可以通过锚点的getRow1()、getCol1()方法拿到图片所在的起始行号和列号(注意:POI中行和列的索引是从0开始的,如果你需要和Excel界面显示的行号列号一致,记得加1),然后用这些信息来命名图片文件,就能轻松区分不同单元格的图片了。
修改后的代码示例
import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.ClientAnchor; import java.io.FileOutputStream; import java.io.IOException; // 假设你已经获取了HSSFSheet对象sheet int i = 0; HSSFPatriarch drawingPatriarch = sheet.getDrawingPatriarch(); if (drawingPatriarch != null) { // 先判断工作表是否有绘图对象,避免空指针 for (HSSFShape shape : drawingPatriarch.getChildren()) { if (shape instanceof HSSFPicture) { HSSFPicture picture = (HSSFPicture) shape; HSSFClientAnchor anchor = (HSSFClientAnchor) picture.getAnchor(); // 获取图片所在的起始行号和列号(POI索引从0开始) int startRow = anchor.getRow1() + 1; // 转为Excel界面的实际行号 int startCol = anchor.getCol1() + 1; // 转为Excel界面的实际列号 HSSFPictureData pictureData = picture.getPictureData(); byte[] imageBytes = pictureData.getData(); // 获取图片的真实扩展名(比如png、jpg、gif),避免硬编码格式出错 String fileExt = pictureData.getFileExtension(); // 用行号列号命名文件,方便区分 String fileName = String.format("image_row%d_col%d_%d.%s", startRow, startCol, i++, fileExt); // 使用try-with-resources自动关闭流,避免资源泄漏 try (FileOutputStream out = new FileOutputStream(fileName)) { out.write(imageBytes); } catch (IOException e) { e.printStackTrace(); } } } }
额外注意事项
- 处理跨单元格图片:如果图片占据了多个单元格,
anchor.getRow1()和anchor.getRow2()会返回不同的行号,getCol1()和getCol2()也会返回不同的列号。你可以根据需求选择用起始位置、结束位置,或者在文件名里标记为跨区域图片(比如image_row1-3_col2-4.png)。 - 适配XLSX格式:如果你处理的是
.xlsx文件,只需要把代码中的HSSF前缀换成XSSF即可(比如XSSFPicture、XSSFClientAnchor),逻辑完全一致。 - 空指针防护:一定要先判断
sheet.getDrawingPatriarch()是否为null,如果工作表中没有图片,这个方法会返回null,直接遍历会抛出空指针异常。
内容的提问来源于stack exchange,提问作者Mayur More
相关产品推荐
相关产品推荐

