使用Apache POI读取Excel中的图片:完整指南
使用Apache POI读取Excel中的图片:完整指南
在处理Excel文件时,我们经常需要提取其中的图片,比如报表中的图表、产品图片等。Apache POI是一个强大的Java库,能够读取和写入Microsoft Office文档。本文将详细介绍如何利用POI读取Excel中的图片,无论老旧的.xls(HSSF)还是新版的.xlsx(XSSF)格式。
前置知识
确保你的项目中已添加POI依赖。Maven示例:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>基本原理
Excel中的图片并不直接嵌入单元格,而是作为独立的对象存在于工作簿的某个位置上,并与单元格通过锚点(Anchor)关联。POI提供了HSSFPatriarch(HSSF)和XSSFDrawing(XSSF)来管理这些图形对象。读取图片的步骤通常包括:
- 打开工作簿
- 获取指定的工作表
- 获取工作表的绘图对象
- 遍历绘图对象中的所有图形,判断是否为图片
- 提取图片数据并保存
读取HSSF(.xls)中的图片
使用HSSFWorkbook和HSSFSheet。示例代码:
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import java.io.*;
import java.util.List;
public class ReadHSSFImages {
public static void main(String[] args) throws IOException {
FileInputStream file = new FileInputStream("old_format.xls");
HSSFWorkbook workbook = new HSSFWorkbook(file);
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFPatriarch patriarch = sheet.getDrawingPatriarch();
if (patriarch != null) {
List shapes = patriarch.getChildren();
for (HSSFShape shape : shapes) {
if (shape instanceof HSSFPicture) {
HSSFPicture picture = (HSSFPicture) shape;
HSSFPictureData picData = picture.getPictureData();
byte[] data = picData.getData();
String ext = picData.suggestFileExtension();
// 保存图片
FileOutputStream out = new FileOutputStream("image." + ext);
out.write(data);
out.close();
}
}
}
workbook.close();
file.close();
}
} 读取XSSF(.xlsx)中的图片
使用XSSFWorkbook和XSSFSheet。注意getDrawingPatriarch返回的是XSSFDrawing。示例代码:
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import java.io.*;
import java.util.List;
public class ReadXSSFImages {
public static void main(String[] args) throws IOException {
FileInputStream file = new FileInputStream("new_format.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(file);
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFDrawing drawing = sheet.getDrawingPatriarch();
if (drawing != null) {
List shapes = drawing.getShapes();
for (XSSFShape shape : shapes) {
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
XSSFPictureData picData = picture.getPictureData();
byte[] data = picData.getData();
String ext = picData.suggestFileExtension();
FileOutputStream out = new FileOutputStream("image." + ext);
out.write(data);
out.close();
}
}
}
workbook.close();
file.close();
}
} 通用方法:统一处理两种格式
由于POI提供了统一的接口(如Picture, PictureData),我们可以编写一个通用的方法,根据工作簿类型分别处理:
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import java.io.*;
import java.util.List;
public class ReadExcelImages {
public static void main(String[] args) throws IOException {
String filePath = "example.xlsx"; // 或 .xls
Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));
Sheet sheet = workbook.getSheetAt(0);
Drawing> drawing = sheet.getDrawingPatriarch();
if (drawing != null) {
for (Shape shape : drawing) {
if (shape instanceof Picture) {
Picture picture = (Picture) shape;
PictureData picData = picture.getPictureData();
byte[] data = picData.getData();
String ext = picData.suggestFileExtension();
FileOutputStream out = new FileOutputStream("image_" + System.currentTimeMillis() + "." + ext);
out.write(data);
out.close();
}
}
}
workbook.close();
}
}常见问题与注意事项
- 没有图片被读取:检查Excel中的图片是否确实是“图片”对象,而非OLE对象或图表。某些图表可能以不同方式存储。
- 锚点偏移:若需要获取图片在单元格中的位置,可以使用
picture.getClientAnchor(),但坐标相对复杂,通常用于更精确的映射。 - 性能考虑:对于大型Excel文件,频繁的I/O和内存操作可能影响性能。可考虑使用流式API如
SXSSFWorkbook(仅限写入)或分批处理。 - 图片格式:
suggestFileExtension()返回的扩展名可能不完全准确,例如EMF、WMF等,但常见格式(PNG、JPEG)通常正确。
扩展应用
除了提取图片,你还可以:
- 替换图片:通过
picture.setPictureData(newPicData)修改。 - 获取图片与单元格间的相对位置,实现数据与图片的关联。
- 结合其他POI功能读取图片的元数据,如文件名、描述等。
总结
使用Apache POI读取Excel中的图片并不复杂,关键在于正确获取绘图对象并遍历其中的图片类形状。通过本文提供的代码,你可以轻松地将Excel中的图片提取出来,存入本地或进行后续处理。记得根据你的具体需求调整异常处理和路径管理。
如果你遇到了其他问题,欢迎在评论区留言讨论。