在业务开发中咱们常常会遇到Excel的导入导出,而 Apache POI 是Java开发者经常使用的API。
【https://poi.apache.org/components/spreadsheet/index.html】html
Universal solution for reading and writing simply Excel based on functional programming and POI EventModel
GridExcel是基于Java8函数式编程和POI EventModel实现的用于Excel简单读写的通用解决方案。java
什么是EventModel?在POI FAQ(常见问题解答)【https://poi.apache.org/help/faq.html#faq-N100C2】官方给出解释:git
The SS eventmodel package is an API for reading Excel files without loading the whole spreadsheet into memory. It does require more knowledge on the part of the user, but reduces memory consumption by more than tenfold. It is based on the AWT event model in combination with SAX. If you need read-only access, this is the best way to do it.
SS eventmodel包是一个用于读取Excel文件而不将整个电子表格加载到内存中的API。 它确实须要用户掌握更多知识,可是将内存消耗减小了十倍以上。 它基于AWT(Abstract Window Toolkit)event model与SAX的结合。 若是您须要只读访问权限,这是最好的方式。程序员
说到函数编程,就不得不提Lambda表达式,若是对Java8中的Lambda不了解或理解不深入,能够看下甲骨文官网给出的这篇文章,【https://www.oracle.com/technetwork/articles/java/architect-lambdas-part1-2080972.html】,我的认为这是Java8 Lambda从入门到进阶最好的文章之一。github
其中函数编程的目的就是实现代码块传递
,即,将方法做为参数在方法间传递。为此,随着Java语言的发展,不断出现一些解决方案:apache
内部类
和匿名内部类
来实现,可是大多数状况下,它们只是被用做事件处理。码块做为对象
(其实是数据)不只有用并且是必要的,可是Java中函数编程仍是很笨拙,它须要成长。注意: 五、六、7参考《深刻理解Java虚拟机》第2版,8.3.3 动态类型语言支持。编程
在POI的使用过程当中,对大多数API User来讲常常面临两个问题,这也是GridExcel致力解决的问题。oracle
将Excel处理逻辑抽取出来,封装成工具类。ide
与大多数Java API同样,POI把更多的精力放在高级功能的处理上,好比Formula(公式)、Conditional Formatting(条件格式)、Zoom(缩放)等。对于仅仅作数据导入导出功能的API User,不多使用这些高级特性,这容许API用户对POI的使用进行简单的封装。函数式编程
不管是读是写,咱们都须要解决Excel中的Columns(列)与Java数据对象Fields(字段)的映射关系,将这种映射关系做为参数(Map对象HashMap或LinkedHashMap),传递给工具类。
对于Columns不难理解,它能够是有序的数字或字母,也能够是其它字符串用来做为首行,表示该列数据的含义。
对于Fields,它的处理须要兼容复杂状况,以下:
value == true?完成:失败;
首先想到,也是大多数封装者都在使用的方式是就是Reflection API,从上文 函数编程 章节咱们了解到,反射重量级,会下降代码的性能,同时对复杂状况的处理支持性不够好。
这种方式能够更好的支持复杂状况,可是反射依然会下降性能,同时注解对数据对象会形成代码侵入,并且对该工具类封装者的其余使用者无疑会增长学习成本。
这种方式也能够很好的支持复杂状况,可是使用匿名内部类的语法显然患有“垂直问题”(这意味着代码须要太多的线条来表达基本概念),太过冗杂。至于性能,应该也不如直接传递函数来的快吧。
这种方式是基于第5条方法调用的字节码指令invokeDynamic实现的,直接传递函数代码块,很好的支持复杂状况,性能较高,代码编写更简单结构更加简洁,并且对数据对象代码零侵入。
内存溢出
或频繁的Full GC
,该如何解决?POI的使用对咱们来讲很常见,对下面两个概念应该并不陌生:
可是对于eventmodel和streaming.SXSSFWorkbook就不多接触了,它们是POI提供的专门用来解决内存占用问题的low level API(低级API),使用它们能够读写数据量很是大的Excel,同时能够避免内存溢出
或频繁的Full GC
。【https://poi.apache.org/compon...】
streaming.SXSSFWorkbook,用来写Excel(是对XSSFWorkbook的封装,仅支持.xlsx),经过滑动窗口来实现,只在内存中保留滑动窗口容许存在的行数,超出的行Rows被写出到临时文件,当调用write(OutputStream stream)
方法写出内容时,再直接从临时内存写出到目标OutputStream。SXSSFWorkbook的使用会产生一些局限性。
基于Java函数编程(Lambda),支持流式API,使用环境Java1.8或更高,学习成本:Lambda
实际上POI官网已经给了用户使用示例,而上述工具只是作了本身的封装实现,让使用更方便。
<dependency> <groupId>com.github.liuhuagui</groupId> <artifactId>gridexcel</artifactId> <version>2.2</version> </dependency>
GridExcel.java提供了多种静态方法,能够直接使用,具体式例可参考测试代码(提供了测试数据和测试文件):
/** * 业务逻辑处理方式三选一: * 1.启用windowListener,并将业务逻辑放在该函数中。 * 2.不启用windowListener,使用get()方法取回所有数据集合,作后续处理。 * 3.readFunction函数,直接放在函数中处理 或 使用final or effective final的局部变量存放这写数据,作后续处理。 * 注意:使用EventModel时readFunction函数的输入为每行的cell值集合List<String>。 * @throws Exception */ @Test public void readXlsxByEventModel() throws Exception { InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("2007.xlsx"); GridExcel.readByEventModel(resourceAsStream,TradeOrder.class,ExcelType.XLSX) .window(2,ts -> System.out.println(JSON.toJSONString(ts)))//推荐在这里执行本身的业务逻辑 .process(cs ->{ TradeOrder tradeOrder = new TradeOrder(); tradeOrder.setTradeOrderId(Long.valueOf(cs.get(0))); Consultant consultant = new Consultant(); consultant.setConsultantName(cs.get(3)); tradeOrder.setConsultant(consultant); tradeOrder.setPaymentRatio(cs.get(16)); return tradeOrder; },1); } /** * 使用Streaming UserModel写出数据到Excel * @throws Exception */ @Test public void writeExcelByStreaming() throws Exception { GridExcel.writeByStreaming(TradeOrder.class) .head(writeFunctionMap())//对象字段到Excel列的映射 .createSheet() .process(MockData.data())//模拟数据。在这里设置业务数据集合。 .write(FileUtils.openOutputStream(new File("/excel/test.xlsx"))); }
Use user model to read excel file. userModel ——
Use event model to read excel file. eventModel ——
Use user model to write excel file. userModel ——
Use API-compatible streaming extension of XSSF to write very large excel file. streaming userModel——
缺点:
在使用工具过程当中出现问题,有功能添加或改动需求的能够向做者提Issue:https://github.com/liuhuagui/...