1. 了解 POI 和 EasyExcel
Java 中,常见的用来操作 Excel 的方式有 2 种:POI、EasyExcel。主要用于:对 Excel 进行导入、导出。
- POI:Apache。一种原生操作 Excel(复杂)
- HSSF : 读写 Microsoft Excel XLS 格式文档
- XSSF : 读写 Microsoft Excel OOXML XLSX 格式文档
- SXSSF : 读写 Microsoft Excel OOXML XLSX 格式文档(优化)
- EasyExcel:更像是一种框架操作 Excel(简单)
它们的区别:
- POI:把要写入的数据全加载到内存中,然后一次性地写数据。容易 OOM
- EasyExcel:一行一行地写
2. POI
使用 POI 操作 Excel 时,API 中有三个不同的对象:HSSF 、XSSF、SXSSF。将它们进行比较:
- HSSF:文档后缀 .xls(03版本的 excel)
- 缺点:只能操作小于或等于 65536 行,否则,会抛出异常
- 优点:过程中写入缓存,不操作磁盘,最后,一次性写入磁盘,速度快
- XSSF:文档后缀 .xlsx(07版本的 excel)
- 缺点:写数据时非常慢(边读边写),非常耗内存,也会发生内存溢出。如:100万条
- 优点:可以写较大的数据量。如:20万条
- SXSSF:文档后缀 .xlsx(07版本的 excel)
- 缺点:需要清除临时文件(((SXSSFWorkbook) workBook).dispose())
- 优点:可以写入更大的数据量。如:100万条。写数据速度快,占用更少的内存
2.1 写操作
创建一个 Maven 项目,引入依赖:
<!--xls 03-->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.9</version>
</dependency>
<!--xlsx 07-->
<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>
代码:
public class ExcelWriteTest {
private String path = System.getProperty("user.dir");// 生成 03 版本的 excelpublic void testWrite03() throws Exception{
// 1.创建一个工作簿Workbook workbook = new HSSFWorkbook();// 2.创建一个工作表Sheet sheet = workbook.createSheet("测试操作Excel03");// 3.创建一个行Row row1 = sheet.createRow(0);// 4.创建一个列Cell cell11 = row1.createCell(0);cell11.setCellValue("姓名");Cell cell12 = row1.createCell(1);cell12.setCellValue("zzc");Row row2 = sheet.createRow(1);Cell cell21 = row2.createCell(0);cell21.setCellValue("统计时间");Cell cell22 = row2.createCell(1);String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");cell22.setCellValue(time);// 生成表FileOutputStream out = new FileOutputStream(path + "测试操作Excel03.xls");workbook.write(out);out.close();System.out.println("测试操作Excel03.xls文件生成完毕!!");}// // 生成 07 版本的 excelpublic void testWrite07() throws Exception{
// 1.创建一个工作簿Workbook workbook = new XSSFWorkbook();// 2.创建一个工作表Sheet sheet = workbook.createSheet("测试操作Excel07");// 3.创建一个行Row row1 = sheet.createRow(0);// 4.创建一个列Cell cell11 = row1.createCell(0);cell11.setCellValue("姓名");Cell cell12 = row1.createCell(1);cell12.setCellValue("zzc");Row row2 = sheet.createRow(1);Cell cell21 = row2.createCell(0);cell21.setCellValue("统计时间");Cell cell22 = row2.createCell(1);String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");cell22.setCellValue(time);// 生成表FileOutputStream out = new FileOutputStream(path + "测试操作Excel07.xlsx");workbook.write(out);out.close();System.out.println("测试操作Excel07.xlsx文件生成完毕!!");}public static void main(String[] args) throws Exception{
ExcelWriteTest excelWriteTest = new ExcelWriteTest();excelWriteTest.testWrite03();excelWriteTest.testWrite07();}
}
生成后的 Excel 文件:
2.2 写操作之优化版本
如果在写入 07 版本的时候,有大量的数据写入,就会有可能出现内存溢出异常,且写入的时间会变得很慢,所以引入了该优化类。
public void testDemo3() throws Exception{
long begin = System.currentTimeMillis();Workbook w = new SXSSFWorkbook();Sheet sheet = w.createSheet("Excel统计表");for (int rowNum = 0; rowNum < 100000; rowNum++) {
Row row = sheet.createRow(rowNum);for (int cellNum = 0; cellNum < 10; cellNum++) {
Cell cell = row.createCell(cellNum);cell.setCellValue(cellNum);}}long end = System.currentTimeMillis();System.out.println("消耗的时间为:"+ (end-begin));FileOutputStream fo = new FileOutputStream(path + "测试表07s.xlsx");w.write(fo);fo.close();
}
2.3 读操作
public class ExcelReadTest {
private String path = System.getProperty("user.dir");public void testRead03() throws Exception{
FileInputStream in = new FileInputStream(path + "测试操作Excel03.xls");Workbook workbook = new HSSFWorkbook(in);Sheet sheet = workbook.getSheetAt(0);Row row = sheet.getRow(0);Cell cell11 = row.getCell(0);Cell cell12 = row.getCell(1);System.out.println(cell11.getStringCellValue());System.out.println(cell12.getStringCellValue());in.close();}public void testRead07() throws Exception{
FileInputStream in = new FileInputStream(path + "测试操作Excel07.xlsx");Workbook workbook = new XSSFWorkbook(in);Sheet sheet = workbook.getSheetAt(0);Row row = sheet.getRow(0);Cell cell11 = row.getCell(0);Cell cell12 = row.getCell(1);System.out.println(cell11.getStringCellValue());System.out.println(cell12.getStringCellValue());in.close();}public static void main(String[] args) throws Exception {
ExcelReadTest excelReadTest = new ExcelReadTest();excelReadTest.testRead03();excelReadTest.testRead07();}
}
2.4 读取不同类型数据的 Excel
Excel 中要读取的数据类型:String、日期、布尔值等
public class ExcelReadTest {
private String path = System.getProperty("user.dir");public void testCellType() throws Exception{
FileInputStream in = new FileInputStream(path + "test.xls");Workbook workbook = new HSSFWorkbook(in);Sheet sheet = workbook.getSheetAt(0);// 获取标题Row rowTitle = sheet.getRow(0);if (null != rowTitle) {
int cellCount = rowTitle.getPhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {
Cell cell = rowTitle.getCell(cellNum);if (null != cell) {
int cellType = cell.getCellType();String cellValue = cell.getStringCellValue();System.out.print(cellValue + "|");}}}System.out.println();// 获取表格的内容int rowCount = sheet.getPhysicalNumberOfRows();for (int rowNum = 1; rowNum < rowCount; rowNum++) {
Row rowData = sheet.getRow(rowNum);if (null != rowData) {
int cellCount = rowTitle.getPhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {
Cell cell = rowData.getCell(cellNum);if (null != cell) {
int cellType = cell.getCellType();String cellValue = "";switch (cellType) {
case Cell.CELL_TYPE_STRING: // 字符串System.out.println("【String】");cellValue = cell.getStringCellValue();break;case Cell.CELL_TYPE_BOOLEAN: // 布尔值System.out.println("【Boolean】");cellValue = String.valueOf(cell.getBooleanCellValue());break;case Cell.CELL_TYPE_BLANK: // 空值System.out.println("【BLANK】");break;case Cell.CELL_TYPE_NUMERIC: // 数字、日期if (HSSFDateUtil.isCellDateFormatted(cell)) {
// 日期System.out.println("【日期】");Date dateCellValue = cell.getDateCellValue();cellValue = new DateTime(dateCellValue).toString("yyyy-MM-dd");} else {
System.out.println("【数字】");// 防止数字过长cell.setCellType(Cell.CELL_TYPE_STRING);cellValue = cell.toString();}break;case Cell.CELL_TYPE_ERROR:System.out.println("【数据类型错误】");break;}System.out.println(cellValue);}}}}in.close();}public static void main(String[] args) throws Exception {
ExcelReadTest excelReadTest = new ExcelReadTest();excelReadTest.testCellType();}
}
3. EasyExcel
3.1 写操作
添加依赖:
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.0.0-beta2</version>
</dependency>
【注意】:一定要去掉 poi 的依赖,否则,会报错!!
public class DemoData {
@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;/*** 忽略这个字段*/@ExcelIgnoreprivate String ignore;//getter/setter
}
public class EasyExcelTest {
private String path = System.getProperty("user.dir");private List<DemoData> data() {
List<DemoData> list = new ArrayList<DemoData>();for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();data.setString("字符串" + i);data.setDate(new Date());data.setDoubleData(0.56);list.add(data);}return list;}public void easyExcelWrite() {
// 写法1String fileName = path + "EasyExcelTest.xlsx";// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());}public static void main(String[] args) {
EasyExcelTest easyExcelTest = new EasyExcelTest();easyExcelTest.easyExcelWrite();}
}
详细操作,请查看文档:EasyExcel