1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > java操作office表格(POI与easyExcelg)

java操作office表格(POI与easyExcelg)

时间:2019-01-22 16:23:02

相关推荐

java操作office表格(POI与easyExcelg)

文章目录

1.POI与easyExcelg概述2.POI-Excel写入3.POI-Excel读取4.EasyExcel操作

1.POI与easyExcelg概述

概述

开发中经常会设计到excel的处理,如导出excel,导入excel到数据库中的功能!

而目前操作Excel目前比较主流的技术有Apache的POI阿里巴巴的easyExcel技术

常用场景

将用户信息,部门信息,等信息导出为excel表格(导出数据)将Excel表格信息录入到网站数据库(习题上传…)大大减轻网站录入量!

Apache PIO

Apache POI官网地址为:/

easyExcelg

easyExcelg官网地址:/alibaba/easyexcel

EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单节省内存著称

EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行一行读取数据,逐个进行解析.

内存问题:POI=100W先加载到内存OOM,在写入文件

下图是EasyExcel与POI在解析Excel文档时的对比图:

2.POI-Excel写入

创建项目

创建一个普通的Maven项目引入pom依赖如下

<dependencies><!-- 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>5.2.2</version></dependency><!-- 日期格式化工具 --><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.10.1</version></dependency><!-- 测试依赖 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency></dependencies>

版本介绍

03(xls)与07(xlsx)版本的写,就是对象不同,方法都是一样的!

需要注意:版本和版本存在兼容性问题!03最多只有65535行!

步骤为:

工作簿工作表行列

基本写入操作

工作薄的接口为Workbook这个接口下有三个实现类为:

HSSFWorkbook(03版本的xls)对象XSSFWorkbook(07版本的xlsx)对象SXSSFWorkbook(升级版增加读写效率)对象

这里除了工作薄的对象不一样其他的操作基本一只代码如:

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.FileOutputStream;import java.io.IOException;public class Test {public static void main(String[] args) throws IOException {//1.创建一个工作簿Workbook hssfWorkbook = new HSSFWorkbook(); //03版本的对象//2.创建一个工作表Sheet testTable = hssfWorkbook.createSheet("小步测试的表");//3.创建一个行Row row = testTable.createRow(0); //表示创建第0行//4.创建一个单元格Cell cell = row.createCell(0); //表示创建第0行的第0个单元格cell.setCellValue("测试数值为:"); //向单元格设值Cell cell1 = row.createCell(1);//表示创建第0行的第1个单元格cell1.setCellValue(666666);Cell cell2 = row.createCell(2);//表示创建第0行第2个单元格cell2.setCellValue("时间为:");Cell cell3 = row.createCell(3);//表示创建第0行第3个单元格cell3.setCellValue(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));//生成一张表FileOutputStream fileOutputStream = new FileOutputStream("crawl/test.xls");//这里为需要输出的文件地址hssfWorkbook.write(fileOutputStream);fileOutputStream.close();}}

注意对象的区别所生成的后缀名需要对应!

大文件写HSSF

缺点:最多只能处理65536行,否则会抛出异常

Invalid row number (65536) outside allowable range (0..65535)

优点:过程中写入缓存,不操作磁盘,最后一次性写入,速度块

03(xls)测试如:

public static void testWrite03BigData() throws IOException {long startTime = System.currentTimeMillis();//1.创建薄HSSFWorkbook hssfWorkbook = new HSSFWorkbook();//2.创建表HSSFSheet sheet = hssfWorkbook.createSheet("小步的测试表");//3.写入数据for (int i = 0; i < 65536; i++) {HSSFRow row = sheet.createRow(i);for (int j = 0; j < 10; j++) {HSSFCell cell = row.createCell(j);cell.setCellValue(i+":"+j);}}long endTime = System.currentTimeMillis();FileOutputStream fileOutputStream = new FileOutputStream("crawl/test.xls");hssfWorkbook.write(fileOutputStream);System.out.println("创建时间为:"+(endTime-startTime)+"毫秒");}

07(xlsx)测试如:

07则没有65536行的限制

public static void testWrite07BigData() throws IOException {long startTime = System.currentTimeMillis();//1.创建薄Workbook hssfWorkbook = new XSSFWorkbook();//2.创建表Sheet sheet = hssfWorkbook.createSheet("小步的测试表");//3.写入数据for (int i = 0; i < 65536; i++) {Row row = sheet.createRow(i);for (int j = 0; j < 10; j++) {Cell cell = row.createCell(j);cell.setCellValue(i+":"+j);}}long endTime = System.currentTimeMillis();FileOutputStream fileOutputStream = new FileOutputStream("crawl/test.xlsx");hssfWorkbook.write(fileOutputStream);System.out.println("创建时间为:"+(endTime-startTime)+"毫秒");}

进行更快的写入测试如:

使用SXSSFWorkbook类进行写入如

public static void testWrite07BigData() throws IOException {long startTime = System.currentTimeMillis();//1.创建薄Workbook hssfWorkbook = new SXSSFWorkbook();//2.创建表Sheet sheet = hssfWorkbook.createSheet("小步的测试表");//3.写入数据for (int i = 0; i < 65536; i++) {Row row = sheet.createRow(i);for (int j = 0; j < 10; j++) {Cell cell = row.createCell(j);cell.setCellValue(i+":"+j);}}long endTime = System.currentTimeMillis();FileOutputStream fileOutputStream = new FileOutputStream("crawl/test.xlsx");//清除临时文件((SXSSFWorkbook)hssfWorkbook).dispose();hssfWorkbook.write(fileOutputStream);System.out.println("创建时间为:"+(endTime-startTime)+"毫秒");}

3.POI-Excel读取

如果需要读取都大致相同,需要与之前一样注意一下03与07版的对象不一就行了如:

基本读取

public static void ReaderData() throws IOException {FileInputStream fileInputStream = new FileInputStream("crawl/testt.xlsx"); //读取的文件HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fileInputStream);HSSFSheet test = hssfWorkbook.getSheetAt(0);HSSFRow row = test.getRow(0);HSSFCell cell = row.getCell(0);//读取值的时候需要注意类型否则会失败System.out.println(cell.getStringCellValue());//如:无法从文本单元格中获取布尔值System.out.println(cell.getBooleanCellValue());}

注意:读取值的时候需要注意类型否则会失败

不同类型读取

public static void ReaderData() throws IOException {FileInputStream fileInputStream = new FileInputStream("crawl/test.xls");HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fileInputStream);HSSFSheet sheet = hssfWorkbook.getSheetAt(0); //获取第零个工作簿int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();//获取这个工作簿有多少行数for (int i = 0; i < physicalNumberOfRows; i++) {HSSFRow row = sheet.getRow(i);//获取每一行int physicalNumberOfCells = row.getPhysicalNumberOfCells();//获取每一行有多少单元格for (int i1 = 0; i1 < physicalNumberOfCells; i1++) {HSSFCell cell = row.getCell(i1);//获取单元格System.out.println(cell.getCellType());//判断单元格的类型值switch (cell.getCellType()){case Cell.CELL_TYPE_NUMERIC://数字类型则需要判断是不是日期if (HSSFDateUtil.isCellDateFormatted(cell)){System.out.println(cell.getDateCellValue());}else {System.out.println(cell.getNumericCellValue());}break;case Cell.CELL_TYPE_STRING:case Cell.CELL_TYPE_BLANK://空白类型和字符串类型System.out.println(cell.getStringCellValue());break;case Cell.CELL_TYPE_BOOLEAN://布尔类型System.out.println(cell.getBooleanCellValue());break;case Cell.CELL_TYPE_ERROR://布尔类型System.out.println(cell.getErrorCellValue());break;}}}}

计算公式(了解即可)

FileInputStream fileInputStream = new FileInputStream("crawl/test.xls");HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fileInputStream);HSSFSheet sheet = hssfWorkbook.getSheetAt(0);HSSFRow row = sheet.getRow(4);HSSFCell cell = row.getCell(0);//拿到计算公司FormulaEvaluator hssfFormulaEvaluator = new HSSFFormulaEvaluator(hssfWorkbook);//输出单元格的内容int cellType = cell.getCellType();switch (cellType){case Cell.CELL_TYPE_FORMULA://如果为公式则String cellFormula = cell.getCellFormula(); //信息System.out.println(cellFormula);//计算CellValue evaluate = hssfFormulaEvaluator.evaluate(cell);String s = evaluate.formatAsString();System.out.println(s);break;}

4.EasyExcel操作

导入依赖

<!--easyExcel--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency>

写入测试

实体类:DemoData.java

import com.alibaba.excel.annotation.ExcelIgnore;import com.alibaba.excel.annotation.ExcelProperty;import lombok.Data;import java.util.Date;@Datapublic class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;//忽略这个字段@ExcelIgnoreprivate String ignore;}

写入测试:

package com.test;import com.alibaba.excel.EasyExcel;import org.junit.Test;import java.util.ArrayList;import java.util.Date;import java.util.List;public class EasyTest {//获取数据public List<DemoData> getData(){List<DemoData> demoData = new ArrayList<>();for (int i = 0; i <10 ; i++) {DemoData demoData1 = new DemoData();demoData1.setString("字符串"+i);demoData1.setDate(new Date());demoData1.setDoubleData(3.1415);demoData.add(demoData1);}return demoData;}//测试方法@Testpublic void testEasy(){String fileName="test/test.xlsx";//写入的地址EasyExcel.write(fileName,DemoData.class).sheet("test").doWrite(getData());}}

读取测试

如果需要读取exel需要进行编写一个监听器如:

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去@Slf4jpublic class DemoDataListener implements ReadListener<DemoData> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 100;/*** 缓存的数据*/private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。*/private DemoDAO demoDAO;public DemoDataListener() {// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数demoDAO = new DemoDAO();}/*** 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来** @param demoDAO*/public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}/*** 这个每一条数据解析都会来调用** @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(DemoData data, AnalysisContext context) {log.info("解析到一条数据:{}", JSON.toJSONString(data));cachedDataList.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}/*** 所有数据解析完成了 都会来调用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}/*** 加上存储数据库*/private void saveData() {log.info("{}条数据,开始存储数据库!", cachedDataList.size());demoDAO.save(cachedDataList);log.info("存储数据库成功!");}}

读取:

//测试方法@Testpublic void testEasy(){String fileName="test/test.xlsx";//写入的地址EasyExcel.read(fileName,DemoData.class,new DemoDataListener()).sheet("test");}

详细文档可查看:/easyexcel/doc/read

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。