java poi学习 Excel的读取与写
一、Excel的写操作
在Excel为我们提供了两种文件类型.XLS和.XLSX文件,这两种文件的读取方式都是一致的.xls文件使用的是HSSF对象,.xlsx使用的是XSSF对象,因为两种方式是一样的,所以我们来看一个HSSF读取的例子
1.导入maven
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency> <!--时间工具类--> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.1</version> </dependency>
2.Excel的写操作
我们先看看我们最终要生成的表格:
import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.ss.usermodel.*; import org.joda.time.DateTime; import java.io.FileOutputStream; public class Demo { public static void main(String[] args) throws Exception { showHSSF(); } /** * 对HSSF表格文件进行写操作 * */ public static void showHSSF() throws Exception { // 首先创建Excel 工作簿 Workbook workbook=new HSSFWorkbook(); // 在Excel工作簿中建一工作表,即创建sheet,取名为测试表格 Sheet sheet=workbook.createSheet("测试表格"); // 创建行,创建了2行 //值为0表示第一行 Row row1=sheet.createRow(0); //值为1表示第二行 Row row2=sheet.createRow(1); //创建单元格样式 CellStyle cellStyle=workbook.createCellStyle(); //设置水平对齐的样式为居中对齐; cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //设置垂直对齐的样式为居中对齐; cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); //创建单元格 //这个单元格位置:1-1 Cell row1Cell1=row1.createCell(0); //对单元格赋值 row1Cell1.setCellValue("姓名"); //设置样式 row1Cell1.setCellStyle(cellStyle); //这个单元格位置:1-2 Cell row1Cell2=row1.createCell(1); row1Cell2.setCellValue("年龄"); row1Cell2.setCellStyle(cellStyle); //这个单元格位置:1-3,1-4的合并单元格 Cell row1Cell3to4=row1.createCell(2); row1Cell3to4.setCellValue("课程"); row1Cell3to4.setCellStyle(cellStyle); //合并单元格(4个参数,分别为起始行,结束行,起始列,结束列) //表格的行和列都是从0开始 CellRangeAddress coursRegion = new CellRangeAddress(0, 0, 2, 3); sheet.addMergedRegion(coursRegion); //这个单元格位置:2-1 Cell row2Cell1=row2.createCell(0); row2Cell1.setCellValue("小明"); row2Cell1.setCellStyle(cellStyle); //这个单元格位置:2-2 Cell row2Cell2=row2.createCell(1); row2Cell2.setCellValue(16); row2Cell2.setCellStyle(cellStyle); //这个单元格位置:2-3 Cell row2Cell3=row2.createCell(2); row2Cell3.setCellValue("语文"); row2Cell3.setCellStyle(cellStyle); //这个单元格位置:2-4 Cell row2Cell4=row2.createCell(3); row2Cell4.setCellValue("数学"); row2Cell4.setCellStyle(cellStyle); //这个单元格位置:1-5、2-5的合并单元格 //要注意的是如果是行与行的合并,必须对第一行中的单元格赋值 Cell row1to2Cell5=row1.createCell(4); String dateTime = new DateTime().toString("yyyy-MM-dd HH:mm:ss"); row1to2Cell5.setCellValue(dateTime); row1to2Cell5.setCellStyle(cellStyle); //合并单元格 //合并单元格(4个参数,分别为起始行,结束行,起始列,结束列) //表格的行和列都是从0开始 CellRangeAddress timeRegion=new CellRangeAddress(0,1,4,4); sheet.addMergedRegion(timeRegion); // 输出文件 FileOutputStream out = new FileOutputStream("E:\\static\\poi\\写操作测试工作簿.xls"); workbook.write(out); // 操作结束,关闭文件 out.close(); System.out.println("文件生成成功"); } }
HSSF文件和XSSF文件两种操作方式是一样的,但是二者又有很大的区别:HSSF写的速度很快,但是最多只能写65536条数据;XSSF能够写大量的数据,但是写的速度很慢,其次XSSF的写操作是直接在内存中写数据,写完后再复制到磁盘,这样就会造成内存溢出的问题,因此为了解决内存溢出问题,poi有为我们提供了一个SXSSF对象进行.xlsx文件的操作。
由于文件是在内存中写的,所以我们需要清理一次内存的操作,关闭文件后添加代码:
((SXSSFWorkbook)workbook).dispose();
二、Excel的读操作
读操作两个文件没有任何区别,但是读操作最重要的是对不同数据类型的读取:
我们要读取的表格内容,需要注意的是H列是F列和G列的求和公式得来的:
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.joda.time.DateTime; import java.io.FileInputStream; import java.io.InputStream; import java.util.Date; public class Demo1 { public static void main(String[] args) throws Exception { String fileName = "E:\\static\\poi\\测试工作簿.xls"; readExcel(fileName); } public static void readExcel(String fileName) throws Exception { //读取文件 InputStream inputStream = new FileInputStream(fileName); //找到工作簿 Workbook workbook = new HSSFWorkbook(inputStream); //找到对应的表格Sheet,0表示第一sheet Sheet sheet = workbook.getSheetAt(0); //得到物理行数 int rowCount = sheet.getPhysicalNumberOfRows(); //根据物理行数,读取每一格的内容 for (int rowNum = 0; rowNum < rowCount; rowNum++) { // 读取每一行的内容 Row rowData = sheet.getRow(rowNum); //空指针判断 if (rowData != null) { // 得到物理列数,总共有多少列 int cellCount = rowData.getPhysicalNumberOfCells(); //读取每个单元格的数据 for (int cellNum = 0; cellNum < cellCount; cellNum++) { //读取了数据是cell对象 //cell对象有多个数据类型 Cell cell = rowData.getCell(cellNum); //空指针判断 if (cell != null) { //获取当前单元格的数据类型 int cellType = cell.getCellType(); //最终读取的值 String cellValue = ""; //根据单元格数据类型来读取数据 switch (cellType) { //字符串类型 case HSSFCell.CELL_TYPE_STRING: System.out.print("字符串类型数据:"); //字符串类型数据获取方法 cellValue = cell.getStringCellValue(); break; //布尔类型,一般不会见到这个类型的值 case HSSFCell.CELL_TYPE_BOOLEAN: System.out.print("布尔类型的数据:"); //布尔类型数据获取方法 cellValue = String.valueOf(cell.getBooleanCellValue()); break; //空数据 case HSSFCell.CELL_TYPE_BLANK: System.out.print("为空的数据:"); break; //数值类型 //数值类型一共有两种,时间戳和数值 case HSSFCell.CELL_TYPE_NUMERIC: //判断当前的数值是否是一个时间戳 if (HSSFDateUtil.isCellDateFormatted(cell)) { System.out.print("日期:"); //时间数据类型转换 Date date = cell.getDateCellValue(); cellValue = new DateTime(date).toString("yyyy-MM-dd HH:mm:ss"); } else { // 不是日期格式,则防止当数字过长时以科学计数法显示 System.out.print("数值类型的数据:"); //数值类型的数据转换成字符串类型 cell.setCellType(HSSFCell.CELL_TYPE_STRING); cellValue = cell.toString(); } break; //公式类型的数据 case HSSFCell.CELL_TYPE_FORMULA: //得到单元格使用的公式 String formula = cell.getCellFormula(); System.out.print("单元格使用的公式是:" + formula); //得到计算的数据 double value = cell.getNumericCellValue(); System.out.print("计算的数据为:" + value); break; //错误的数据类型 case Cell.CELL_TYPE_ERROR: System.out.print("数据类型错误"); break; } System.out.println(cellValue); } } } } inputStream.close(); } }
测试内容: