java 导出Excel 大数据量,自己经验总结!
分析导出实现代码,XLSX支持:
- /**
- * 生成<span style="white-space: normal; background-color: #ffffff;">XLSX</span>,2007版本的excel,每个sheet无6.5W的行数限制,但是到了一定数量,可能内存溢出,
- * 次方法适合在预计10W以下的数据导出时使用,本机测试,14W可以导出。列数量在8列左右
- *
- * @param fileOut
- * 输出流
- * @param sheetMap
- * 要设置的数据信息
- * @throws SQLException
- */
- public static void createXSLXByResultSet(OutputStream fileOut, WriteXLSBean... beans)
- throws SQLException {
- try {
- //重点 Workbook
- Workbook wb = new XSSFWorkbook();
- for (int i = 0, len = beans.length; i < len; i++) {
- WriteXLSBean xlsBean = beans[i];
- Sheet sheet = wb.createSheet(xlsBean.getSheetName());
- ResultSet rs = xlsBean.getRs();
- ResultSetMetaData rsmd = rs.getMetaData();
- TypeHandlerRegistry tr = BeanContext.tr;
- Map<String, String> th = xlsBean.getTh();
- int index = 0;
- while (rs.next()) {
- long t1 = System.currentTimeMillis();
- org.apache.poi.ss.usermodel.Row row = sheet
- .createRow(index);
- for (int j = 0, numberOfColumns = rsmd.getColumnCount(); j < numberOfColumns; j++) {
- String key = rsmd.getColumnLabel(j + 1).toLowerCase();
- if (th.containsKey(key)) {
- TypeHandler<?> type = tr.getTypeHandler(JdbcType
- .forCode(rsmd.getColumnType(j + 1)));
- Object obj = type.getResult(rs, key);
- row.createCell(j).setCellValue(obj == null ? ""
- : obj.toString());
- }
- }
- System.out.println(index + " :"
- + (System.currentTimeMillis() - t1));
- index++;
- }
- }
- //重点 Workbook
- wb.write(fileOut);
- } catch (IOException e) {
- e.printStackTrace();
- throw new ServiceRunTimeException("生产xls文档错误", e);
- } finally {
- }
- }
在上面 标注了重点的两处,分别是:
1.构建一个Excel对象
2.将该对象写入一个OutPutStream
而在构建过程中,没有地方写入OutPutSteam ,也就是说必须在内存中构建整个 Excel,才能进行写出操作,在大数据量情况下,这样将导致所有数据加载到内存中,而不能输出,导致最后 内存溢出。
根据运行环境不用,可能内存溢出的 情况不同
根据情况,如果数据量达到10W以上,建议使用
1、多个Excel,每个Excel一个Sheet,因为所有Sheet都是Workbook的组成部分。如果不分多个Excel,即使分Sheet也没用,
2、每个Excel中列数适中,比如: 5W行每个Excel档,实现分多次导出和分页查询原理一样
3、对多个Excel导出到一个临时目录,并通过程序压缩,然后提供给客户下载
2003版通过数据库结果存到List中,然后进行生产:Table 就是List Row 是Map
- /**
- * 生产xls,2003版本的excel,每个sheet有6.5W的行数限制
- *
- * @param fileOut
- * 输出流,未关闭
- * @param sheetMap
- * 要导出的数据信息
- */
- public static void createXSLByMap(OutputStream fileOut, Map<String, Table<Row<String, Object>>> sheetMap) {
- try {
- HSSFWorkbook wb = new HSSFWorkbook();
- Set<String> keys = sheetMap.keySet();
- for (Iterator<String> iterator = keys.iterator(); iterator
- .hasNext();) {
- String SheetKey = iterator.next();
- Sheet sheet = wb.createSheet(SheetKey);
- List<Row<String, Object>> sheetRows = sheetMap.get(SheetKey);
- for (int i = 0, len = sheetRows.size(); i < len; i++) {
- Map<String, Object> cellMap = sheetRows.get(i);
- Set<String> cellSet = cellMap.keySet();
- org.apache.poi.ss.usermodel.Row row = sheet.createRow(i);
- int j = 0;
- for (Iterator<String> iterCell = cellSet.iterator(); iterCell
- .hasNext(); j++) {
- String cellKey = iterCell.next();
- Object obj = cellMap.get(cellKey);
- row.createCell(j).setCellValue(obj == null ? ""
- : obj.toString());
- }
- }
- }
- wb.write(fileOut);
- } catch (IOException e) {
- e.printStackTrace();
- throw new ServiceRunTimeException("生产xls文档错误", e);
- } finally {
- }
- }
新版本 POI+office 2007版本excel可以导出几十万条而不内存溢出,详细见:
导出大量数据到 excel 的 xlsx文件
- static String src="abcdefafslfelgtryjukjhgfdadertjDSFGHJKJGHFERTUIOabcdefafslfelgtryjukjhgfdadertjDSFGHJKdertjDSFGHJKJGHFERTUIOabcdefafslfelgtryjukjhgfdadertjDSFGHJKJGHFERTUIO";
- public static void main(String[] args) throws Throwable {
- SXSSFWorkbook wb = new SXSSFWorkbook(100); // 这里100是在内存中的数量,如果大于此数量时,会写到硬盘,以避免在内存导致内存溢出
- Sheet sh = wb.createSheet();
- for (int rownum = 0; rownum < 1000000; rownum++) {
- Row row = sh.createRow(rownum);
- for (int cellnum = 0; cellnum < 10; cellnum++) {
- Cell cell = row.createCell(cellnum);
- String address = new CellReference(cell).formatAsString();
- cell.setCellValue(address+src.substring(rownum%10*10+1, (rownum%10+1)*10));
- }
- }
- File file = new File("F:/aa.xlsx");
- file.createNewFile();
- FileOutputStream out = new FileOutputStream(file);
- wb.write(out);
- out.close();
- }
内存使用情况:
根据以上前辈经验,自己在结果自身需求考虑,整合出一个工具。解决了excle表.xls格式行数65535行的限制。我实现的形式是导出一张表,里面有多页aaarticlea/png;base64,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" alt="" />(我是已65000为一页)
这里是用反射来使用所有传入进行的实体的属性的值。这里只针对String和基本数据类型。如有自己定义的类型需要自己加上。
- package com.tommy.fundation.util;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
- public class RelectUtil {
- public static <T> List<Object> reflectEntity(T model,Class<?> cals) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchFieldException{
- List<Object> list = new ArrayList<Object>();
- Field[] field = model.getClass().getDeclaredFields(); //获取实体类的所有属性,返回Field数组
- for(int j=0 ; j<field.length ; j++){ //遍历所有属性
- String nam = field[j].getName(); //获取属性的名字
- String name = nam;
- name = name.substring(0,1).toUpperCase()+name.substring(1);
- String type = field[j].getGenericType().toString(); //获取属性的类型
- if(type.equals("class java.lang.String")){ //如果type是类类型,则前面包含"class ",后面跟类名
- Method m = model.getClass().getMethod("get"+name);
- String value = (String) m.invoke(model); //调用getter方法获取属性值
- if(value != null){
- list.add(value);
- }else{
- list.add("");
- }
- }
- if(type.equals("class java.lang.Integer")){
- Method m = model.getClass().getMethod("get"+name);
- Integer value = (Integer) m.invoke(model);
- if(value != null){
- list.add(value);
- }else{
- list.add("");
- }
- }
- if(type.equals("class java.lang.Short")){
- Method m = model.getClass().getMethod("get"+name);
- Short value = (Short) m.invoke(model);
- if(value != null){
- list.add(value);
- }else{
- list.add("");
- }
- }
- if(type.equals("class java.lang.Double")){
- Method m = model.getClass().getMethod("get"+name);
- Double value = (Double) m.invoke(model);
- if(value != null){
- list.add(value);
- }else{
- list.add("");
- }
- }
- if(type.equals("class java.lang.Boolean")){
- Method m = model.getClass().getMethod("get"+name);
- Boolean value = (Boolean) m.invoke(model);
- if(value != null){
- list.add(value);
- }else{
- list.add("");
- }
- }
- if(type.equals("class java.util.Date")){
- Method m = model.getClass().getMethod("get"+name);
- Date value = (Date) m.invoke(model);
- if(value != null){
- list.add(value);
- }else{
- list.add("");
- }
- }
- }
- return list;
- }
- }
下面将是重点实现导出excel表
- package com.tommy.fundation.util;
- import java.io.OutputStream;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.poi.hssf.record.formula.functions.T;
- import org.apache.poi.hssf.usermodel.HSSFRow;
- import org.apache.poi.hssf.usermodel.HSSFSheet;
- import org.apache.poi.hssf.usermodel.HSSFWorkbook;
- @SuppressWarnings("hiding")
- public class ExportExcel<T> {
- /**
- * 导出多张excel表,解决xls格式行数65535的限制
- * @author OnlyOne
- * @param response
- * @param list 需要处理的list数据集合
- * @throws Exception
- */
- @SuppressWarnings("deprecation")
- public void doExcel(HttpServletResponse response,List<T> list,String fileName) throws Exception {
- OutputStream os = response.getOutputStream();//获取输出流
- response.reset();
- // 设置下载头部信息。Content-disposition为属性名。attachment表示以附件方式下载,如果要在页面中打开,则改为inline。filename为文件名
- response.setHeader("Content-disposition", "attachment; filename=excell.xls");
- response.setContentType("application/msexcel");
- Map<Integer, List<T>> sheetMap = daData(list);
- HSSFWorkbook wb = new HSSFWorkbook();
- Set<Integer> keys = sheetMap.keySet();
- for (Iterator<Integer> iterator = keys.iterator(); iterator.hasNext();) {
- Integer SheetKey = iterator.next();
- HSSFSheet sheet = wb.createSheet((fileName+SheetKey).toString());
- List<T> sheetRows = sheetMap.get(SheetKey);
- for (int i = 0, len = sheetRows.size(); i < len; i++) {
- T en = (T) sheetRows.get(i);
- List<Object> dataList = RelectUtil.<T>reflectEntity(en, en.getClass());
- HSSFRow row = sheet.createRow(i);
- row.createCell(0).setCellValue(String.valueOf(i));
- for(int m=0; m<dataList.size(); m++){
- row.createCell(m+1).setCellValue(dataList.get(m).toString());
- }
- }
- }
- wb.write(os);
- }
- /**
- * 此方法将数据集合按65000个进行分割成多个子集合
- * @author OnlyOne
- * @param list 需要处理的list数据集合
- * @return
- */
- public Map<Integer, List<T>> daData(List<T> list){
- int count = list.size()/65000;
- int yu = list.size() % 65000;
- Map<Integer, List<T>> map = new HashMap<Integer, List<T>>();
- for (int i = 0; i <= count; i++) {
- List<T> subList = new ArrayList<T>();
- if (i == count) {
- subList = list.subList(i * 65000, 65000 * i + yu);
- } else {
- subList = list.subList(i * 65000, 65000 * (i + 1)-1);
- }
- map.put(i, subList);
- }
- return map;
- }
- }
在Java中调用的方式
- @RequestMapping(value = "/doExcel", method = RequestMethod.GET)
- public void doExcel(HttpServletResponse response,HttpServletRequest request) throws Exception {
- List<Enrolltg> list = enrolltgService.findAll();
- new ExportExcel<Enrolltg>().doExcel(response, list, "黑白淡奶");
- }
大功搞成,以后再也不会为了数据量太大而导不出来烦恼了!!!
需要的包 poi-3.2-FINAL-20081019.jar
java 导出Excel 大数据量,自己经验总结!的更多相关文章
- java 导出Excel 大数据量,自己经验总结!(二)
在上一次的基础上加上了样式,以及中文列名 package com.tommy.fundation.util; import java.io.OutputStream; import java.util ...
- java excel大数据量导入导出与优化
package com.hundsun.ta.utils; import java.io.File; import java.io.FileOutputStream; import java.io.I ...
- java导出excel模板数据
Java导出excel数据模板,这里直接贴代码开发,流程性的走下去就是步骤: String[] colName=new String[]{"期间","科目代码" ...
- ASP.NET MVC导出excel(数据量大,非常耗时的,异步导出)
要在ASP.NET MVC站点上做excel导出功能,但是要导出的excel文件比较大,有几十M,所以导出比较费时,为了不影响对界面的其它操作,我就采用异步的方式,后台开辟一个线程将excel导出到指 ...
- MVC学习笔记---MVC导出excel(数据量大,非常耗时的,异步导出)
要在ASP.NET MVC站点上做excel导出功能,但是要导出的excel文件比较大,有几十M,所以导出比较费时,为了不影响对界面的其它操作,我就采用异步的方式,后台开辟一个线程将excel导出到指 ...
- 使用NPOI或POI 导出Excel大数据(百万级以上),导致内存溢出的解决方案(NPOI,POI)
使用工具:POI(JAVA),NPOI(.Net) 致谢博主 Crazy_Jeff 提供的思路 一.问题描述: 导出任务数据量近100W甚至更多,导出的项目就会内存溢出,挂掉. 二.原因分析: 1.每 ...
- Excel大数据量分段导入到Oracle
客户需要将一个具有2W多条数据的Excel表格中的数据导入到Oracle数据库的A表中,开始采用的是利用Oledb直接将数据读入到DataTable中,然后通过拼接InserInto语句来插入到数据库 ...
- POI 生成excel(大数据量) SXSSF
使用POI 的SXSSF (Streaming Usermodel API)生成较大的excel,同时开启压缩 import junit.framework.Assert; import org.ap ...
- NPOI大数据量多个sheet导出源码(原)
代码如下: #region NPOI大数据量多个sheet导出 /// <summary> /// 大数据量多个sheet导出 /// </summary> /// <t ...
随机推荐
- SQL Server 数据查询 整理
一.使用SELECT检索数据 数据查询是SQL语言的中心内容,SELECT 语句的作用是让数据库服务器根据客户要求检索出所需要的信息资料,并按照规定的格式进行整理,返回给客户端. SELECT 语句的 ...
- HGE游戏引擎之实战篇,渐变的游戏开场
#include <hge.h> #include "menuitem.h" //#include <hgefont.h> #include <hge ...
- iptables的四表五链
iptables只是Linux防火墙的管理工具而已,位于/sbin/iptables.真正实现防火墙功能的是netfilter,它是Linux内核中实现包过滤的内部结构. iptables包含4个表, ...
- Linux终端乱码的解决办法
用SSH连接Linux时经常会遇到乱码的情况,痛苦了好久,在网上找到一个解决办法,编辑~/.bash_profile文件,加入下面两行: LANG="zh_CN.GB18030" ...
- 坑爹的VS2012
2.2.2.如果卸载 Visual Studio 2010 Service Pack 1,则必须先重新安装 Visual Studio 2010,然后才能再次安装 SP1 如果卸载 Visual St ...
- ojdbc5.jar
ojdbc5.jar:http://files.cnblogs.com/files/xiluhua/ojdbc5.rar
- Docker Centos安装Redis以及问题处理
之前一篇文章 Redis安装及主从配置 介绍了redis的安装配置,另一篇文件介绍了 Docker Centos安装Openssh .今天将两篇文件结合一下——在Docker Centos环境下搭建r ...
- SQL Server 2005 日志文件过大处理
由于安装的时候没有计划好空间,默认装在系统盘,而且又没有做自动备份.截断事务日志等,很快LDF文件就达到十几G,或者几十G ,此时就不得不处理了. 备份和计划就不说了,现在就说下怎么把它先删除吧: 1 ...
- ACM第一站————快速排序
转载请注明出处,谢谢!http://www.cnblogs.com/Asimple/p/5455125.html 快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. ...
- C#的OpenFileDialog和SaveFileDialog的常见用法(转)
OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.InitialDirectory = ...