阅读完需:约 11 分钟
一、POI概述
Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
结构:
- HSSF - 提供读写Microsoft Excel格式档案的功能。
- XSSF - 提供读写Microsoft Excel OOXML格式档案的功能。
- SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。
- HWPF - 提供读写Microsoft Word格式档案的功能。
- HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
- HDGF - 提供读写Microsoft Visio格式档案的功能。
使用必须引入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
二、HSSF概况
HSSF 是Horrible SpreadSheet Format的缩写,通过HSSF,你可以用纯Java代码来读取、写入、修改Excel文件。HSSF 为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”。
三、 POI EXCEL文档结构类
- HSSFWorkbook excel文档对象
- HSSFSheet excel的sheet
- HSSFRow excel的行
- HSSFCell excel的单元格
- HSSFFont excel字体
- HSSFName 名称
- HSSFDataFormat 日期格式
- HSSFHeader sheet头
- HSSFFooter sheet尾
- HSSFCellStyle cell样式
- HSSFDateUtil 日期
- HSSFPrintSetup 打印
- HSSFErrorConstants 错误信息表
四、EXCEL的读写操作
1、读取“区域数据.xls”并储存于list集合中,“区域数据.xls”如下图

public List<Area> importXLS(){
ArrayList<Area> list = new ArrayList<>();
try {
//1、获取文件输入流
InputStream inputStream = new FileInputStream("/Users/Shared/区域数据.xls");
//2、获取Excel工作簿对象
HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
//3、得到Excel工作表对象
HSSFSheet sheetAt = workbook.getSheetAt(0);
//4、循环读取表格数据
for (Row row : sheetAt) {
//首行(即表头)不读取
if (row.getRowNum() == 0) {
continue;
}
//读取当前行中单元格数据,索引从0开始
String areaNum = row.getCell(0).getStringCellValue();
String province = row.getCell(1).getStringCellValue();
String city = row.getCell(2).getStringCellValue();
String district = row.getCell(3).getStringCellValue();
String postcode = row.getCell(4).getStringCellValue();
Area area = new Area();
area.setCity(city);
area.setDistrict(district);
area.setProvince(province);
area.setPostCode(postcode);
list.add(area);
}
//5、关闭流
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
2、导出数据到“区域数据.xls”文件中,页面数据如下图:

public void exportExcel() throws IOException {
Page<Area> page = areaService.pageQuery(null);
List<Area> list = page.getContent();
//1.在内存中创建一个excel文件
HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
//2.创建工作簿
HSSFSheet sheet = hssfWorkbook.createSheet();
//3.创建标题行
HSSFRow titlerRow = sheet.createRow(0);
titlerRow.createCell(0).setCellValue("省");
titlerRow.createCell(1).setCellValue("市");
titlerRow.createCell(2).setCellValue("区");
titlerRow.createCell(3).setCellValue("邮编");
titlerRow.createCell(4).setCellValue("简码");
titlerRow.createCell(5).setCellValue("城市编码");
//4.遍历数据,创建数据行
for (Area area : list) {
//获取最后一行的行号
int lastRowNum = sheet.getLastRowNum();
HSSFRow dataRow = sheet.createRow(lastRowNum + 1);
dataRow.createCell(0).setCellValue(area.getProvince());
dataRow.createCell(1).setCellValue(area.getCity());
dataRow.createCell(2).setCellValue(area.getDistrict());
dataRow.createCell(3).setCellValue(area.getPostcode());
dataRow.createCell(4).setCellValue(area.getShortcode());
dataRow.createCell(5).setCellValue(area.getCitycode());
}
//5.创建文件名
String fileName = "区域数据统计.xls";
//6.获取输出流对象
HttpServletResponse response = ServletActionContext.getResponse();
ServletOutputStream outputStream = response.getOutputStream();
//7.获取mimeType
ServletContext servletContext = ServletActionContext.getServletContext();
String mimeType = servletContext.getMimeType(fileName);
//8.获取浏览器信息,对文件名进行重新编码
HttpServletRequest request = ServletActionContext.getRequest();
fileName = FileUtils.filenameEncoding(fileName, request);
//9.设置信息头
response.setContentType(mimeType);
response.setHeader("Content-Disposition","attachment;filename="+fileName);
//10.写出文件,关闭流
hssfWorkbook.write(outputStream);
hssfWorkbook.close();
}
工具类
public class FileUtils {
public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
String agent = request.getHeader("User-Agent"); //获取浏览器
if (agent.contains("Firefox")) {
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8"))
+ "?=";
} else if(agent.contains("MSIE")) {
filename = URLEncoder.encode(filename, "utf-8");
} else if(agent.contains ("Safari")) {
filename = new String (filename.getBytes ("utf-8"),"ISO8859-1");
} else {
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
写出xls文件:

五、 EXCEL常用操作方法
1、 得到Excel常用对象
POIFSFileSystem fs=newPOIFSFileSystem(new FileInputStream("d:/test.xls"));
//得到Excel工作簿对象
HSSFWorkbook wb = new HSSFWorkbook(fs);
//得到Excel工作表对象
HSSFSheet sheet = wb.getSheetAt(0);
//得到Excel工作表的行
HSSFRow row = sheet.getRow(i);
//得到Excel工作表指定行的单元格
HSSFCell cell = row.getCell((short) j);
cellStyle = cell.getCellStyle();//得到单元格样式
2、建立Excel常用对象
HSSFWorkbook wb = new HSSFWorkbook();//创建Excel工作簿对象
HSSFSheet sheet = wb.createSheet("new sheet");//创建Excel工作表对象
HSSFRow row = sheet.createRow((short)0); //创建Excel工作表的行
cellStyle = wb.createCellStyle();//创建单元格样式
row.createCell((short)0).setCellStyle(cellStyle); //创建Excel工作表指定行的单元格
row.createCell((short)0).setCellValue(1); //设置Excel工作表的值
3、设置sheet名称和单元格内容
wb.setSheetName(1, "第一张工作表",HSSFCell.ENCODING_UTF_16);
cell.setEncoding((short) 1);
cell.setCellValue("单元格内容");
4、取得sheet的数目
wb.getNumberOfSheets()
5、 根据index取得sheet对象
HSSFSheet sheet = wb.getSheetAt(0);
6、取得有效的行数
int rowcount = sheet.getLastRowNum();
7、取得一行的有效单元格个数
row.getLastCellNum();
8、单元格值类型读写
cell.setCellType(HSSFCell.CELL_TYPE_STRING); //设置单元格为STRING类型
cell.getNumericCellValue();//读取为数值类型的单元格内容
9、设置列宽、行高
sheet.setColumnWidth((short)column,(short)width);
row.setHeight((short)height);
10、添加区域,合并单元格
Region region = new Region((short)rowFrom,(short)columnFrom,(short)rowTo
,(short)columnTo);//合并从第rowFrom行columnFrom列
sheet.addMergedRegion(region);// 到rowTo行columnTo的区域
//得到所有区域
sheet.getNumMergedRegions()
11、保存Excel文件
FileOutputStream fileOut = new FileOutputStream(path);
wb.write(fileOut);
12、根据单元格不同属性返回字符串数值
public String getCellStringValue(HSSFCell cell) {
String cellValue = "";
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_STRING://字符串类型
cellValue = cell.getStringCellValue();
if(cellValue.trim().equals("")||cellValue.trim().length()<=0)
cellValue=" ";
break;
case HSSFCell.CELL_TYPE_NUMERIC: //数值类型
cellValue = String.valueOf(cell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA: //公式
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
cellValue = String.valueOf(cell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_BLANK:
cellValue=" ";
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
break;
case HSSFCell.CELL_TYPE_ERROR:
break;
default:
break;
}
return cellValue;
}
13、常用单元格边框格式
HSSFCellStyle style = wb.createCellStyle();
style.setBorderBottom(HSSFCellStyle.BORDER_DOTTED);//下边框
style.setBorderLeft(HSSFCellStyle.BORDER_DOTTED);//左边框
style.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
14、设置字体和内容位置
HSSFFont f = wb.createFont();
f.setFontHeightInPoints((short) 11);//字号
f.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);//加粗
style.setFont(f);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//左右居中
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//上下居中
style.setRotation(short rotation);//单元格内容的旋转的角度
HSSFDataFormat df = wb.createDataFormat();
style1.setDataFormat(df.getFormat("0.00%"));//设置单元格数据格式
cell.setCellFormula(string);//给单元格设公式
style.setRotation(short rotation);//单元格内容的旋转的角度
15、插入图片
//先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
BufferedImage bufferImg = ImageIO.read(new File("ok.jpg"));
ImageIO.write(bufferImg,"jpg",byteArrayOut);
//读进一个excel模版
FileInputStream fos = new FileInputStream(filePathName+"/stencil.xlt");
fs = new POIFSFileSystem(fos);
//创建一个工作薄
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFSheet sheet = wb.getSheetAt(0);
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
HSSFClientAnchor anchor = new HSSFClientAnchor(0,0,1023,255,(short) 0,0,(short)10,10);
patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
16、调整工作表位置
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("format sheet");
HSSFPrintSetup ps = sheet.getPrintSetup();
sheet.setAutobreaks(true);
ps.setFitHeight((short)1);
ps.setFitWidth((short)1);
例子:
写入一个Excel
public class ExcelWriter {
//先要有个路劲
static String path="F:\\demo\\javapoi\\demopoi\\";
public static void main(String[] args) throws IOException {
//1,创建一个工作薄
Workbook wordkbook =new HSSFWorkbook();
//表名
Sheet sheet=wordkbook.createSheet("灰灰统计表");
//创建行
Row row1=sheet.createRow(0);
//4.创建一个单元格
Cell cell = row1.createCell(0);
cell.setCellValue("今日新增观众");
Cell cell2 = row1.createCell(1);
cell2.setCellValue("卢本伟");
//创建行
Row row2=sheet.createRow(1);
//4.创建一个单元格
Cell cell3 = row2.createCell(0);
cell3.setCellValue("统计时间");
Cell cell24= row2.createCell(1);
String time=new DateTime().toString("yyyy-MM-dd HH:mm:ss");
cell24.setCellValue(time);
//生成一张表 03是xls 07是xlsx
FileOutputStream fileOutputStream = new FileOutputStream(path + "灰灰统计表07.xlsx");
wordkbook.write(fileOutputStream);
fileOutputStream.close();
System.out.println("灰灰统计表03已生成");
}
}
上面写完后会在项目目录下生成一个表格
读取我们所写的表格
这个操作跟上述的写并没有什么不同,不同就是方法是get而不是set
static String path="F:\\demo\\javapoi\\demopoi";
@Test
public void testread03() throws IOException {
//Sheet sheet=workbook.createSheet("统计表");
//sheet操作表中元素
FileInputStream fileInputStream = new FileInputStream(path + "灰灰统计表03.xls");
Workbook workbook=new HSSFWorkbook(fileInputStream);
Sheet sheet = workbook.getSheetAt(0);
Sheet sheet2 = workbook.getSheet("灰灰统计表");
Row row = sheet.getRow(1);
Cell cell = row.getCell(0);
Cell cell2 = row.getCell(1);
System.out.println(cell.getStringCellValue());
System.out.println(cell2.getNumericCellValue());
fileInputStream.close();
}
这里值得注意的是,使用表格对象要注意三种创建方式
POI-HSSF
POI-XSSF
SXSSF
HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数65536,最大列数256。
XSSF:Excel2007版本开始,扩展名为.xlsx。一个sheet最大行数1048576,最大列数16384。
SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。
Excel版本兼容性是向下兼容。
在读取数据的时候我们需要先判断值类型,才能用对应API
FileInputStream fileInputStream = new FileInputStream(path + "数据表07.xlsx");
Workbook workbook=new XSSFWorkbook(fileInputStream);
Sheet sheet = workbook.getSheetAt(0);
Row rowTitle = sheet.getRow(0);
if(rowTitle!=null){
int cellCount=rowTitle.getPhysicalNumberOfCells(); //拿到第row行的那一行的总个数
for (int i = 0; i <cellCount ; i++) { //循环个数取出
Cell cell = rowTitle.getCell(i);
if(cell!=null){ //如果不等于空取出值
int cellType = cell.getCellType(); //这里是知道我们标题是String,考虑不确定的时候怎么取
String cellValue = cell.getStringCellValue();
System.out.print(cellValue+"|");
}
}
System.out.println();
}
下面接着读取对应的数据,这里就需要我们刚刚讲的类型判断
int cellType=cell.getCellType();利用这个,然后判断它的XSSFCell类型再具体输出
//获取表中内容
int rowCount=sheet.getPhysicalNumberOfRows();
for(int rowNum=1;rowNum<rowCount;rowNum++){
Row rowData=sheet.getRow(rowNum); //取出对应的行
if(rowData!=null){
int cellCount=rowTitle.getPhysicalNumberOfCells();
for(int cellNum=0;cellNum<cellCount;cellNum++){
System.out.print("["+(rowNum+1+"-"+(cellNum+1)+"]"));
Cell cell = rowData.getCell(cellNum);
//匹配数据类型
if(cell!=null){
int cellType=cell.getCellType();
switch (cellType){
case XSSFCell.CELL_TYPE_STRING: System.out.print("字符串:"+cell.getStringCellValue());break;
case XSSFCell.CELL_TYPE_BOOLEAN: System.out.print("布尔:"+cell.getBooleanCellValue());break;
case XSSFCell.CELL_TYPE_NUMERIC:
if(HSSFDateUtil.isCellDateFormatted(cell)){
System.out.println("日期格式:"+new DateTime(cell.getDateCellValue()).toString("yyyy-MM-dd HH:mm:ss"));break;
}else
cell.setCellType(XSSFCell.CELL_TYPE_STRING);
System.out.print("整形:"+cell.toString());break;
case XSSFCell.CELL_TYPE_BLANK: System.out.print("空");break;
case XSSFCell.CELL_TYPE_ERROR: System.out.print("数据类型错误");break;
case Cell.CELL_TYPE_FORMULA:
String formula=cell.getCellFormula();
System.out.println("公式:"+formula);
//
CellValue evaluate = formulaEvaluator.evaluate(cell);
String cellValue=evaluate.formatAsString();
System.out.println(cellValue);
break;
default:break;
}
}
}
}
}
fileInputStream.close();