`

POI大数据量导出

阅读更多

前段时间,做POI导出的时候,应为数据量大(十万条数据),所以总是出现OOM错误,在网上找到了解决办法,大数据量导出Excel的方案:http://devbbs.doit.com.cn/redirect.php?tid=46&goto=lastpost
解决大批量数据导出Excel产生内存溢出的方案:http://cnaning.iteye.com/blog/347158
解决大批量数据导出Excel产生内存溢出的方案(二):http://cnaning.iteye.com/blog/347160

  1. import java.io.ByteArrayInputStream;   
  2. import java.io.File;   
  3. import java.io.FileOutputStream;   
  4. import java.io.IOException;   
  5. import java.io.InputStream;   
  6. import java.io.OutputStream;   
  7. import java.util.ArrayList;   
  8. import java.util.Collections;   
  9. import java.util.HashMap;   
  10. import java.util.Iterator;   
  11. import java.util.List;   
  12. import java.util.Map;   
  13.   
  14. import org.apache.log4j.Logger;   
  15. import org.apache.poi.hssf.model.Sheet;   
  16. import org.apache.poi.hssf.model.Workbook;   
  17. import org.apache.poi.hssf.record.CellValueRecordInterface;   
  18. import org.apache.poi.hssf.record.LabelRecord;   
  19. import org.apache.poi.hssf.record.LabelSSTRecord;   
  20. import org.apache.poi.hssf.record.Record;   
  21. import org.apache.poi.hssf.record.RowRecord;   
  22. import org.apache.poi.hssf.record.SSTRecord;   
  23. import org.apache.poi.hssf.record.UnicodeString;   
  24. import org.apache.poi.poifs.filesystem.POIFSFileSystem;   
  25. import org.apache.struts.taglib.html.RewriteTag;   
  26.   
  27. @SuppressWarnings("unchecked")   
  28. public class XlsMergeUtil {   
  29.     private static Logger logger = Logger.getLogger(XlsMergeUtil.class);   
  30.   
  31.     /**  
  32.      * 将多个Xls文件合并为一个,适用于只有一个sheet,并且格式相同的文档  
  33.      *   
  34.      * @param inputs  
  35.      *            输入的Xls文件,第一个XLS文件必须给出足够sheet空间 例如,总共200000行数据,第一个文件至少3个空白sheet  
  36.      * @param out  
  37.      *            输出文件  
  38.      */  
  39.     public static void merge(InputStream[] inputs, OutputStream out) {   
  40.         if (inputs == null || inputs.length <= 1) {   
  41.             throw new IllegalArgumentException("没有传入输入流数组,或只有一个输入流.");   
  42.         }   
  43.   
  44.         List<Record> rootRecords = getRecords(inputs[0]);   
  45.         Workbook workbook = Workbook.createWorkbook(rootRecords);   
  46.         List<Sheet> sheets = getSheets(workbook, rootRecords);   
  47.         if (sheets == null || sheets.size() == 0) {   
  48.             throw new IllegalArgumentException("第一篇文档的格式错误,必须有至少一个sheet");   
  49.         }   
  50.         // 以第一篇文档的第一个sheet为根,以后的数据都追加在这个sheet后面   
  51.         Sheet rootSheet = sheets.get(0);   
  52.         int rootRows = getRowsOfSheet(rootSheet); // 记录第一篇文档的行数,以后的行数在此基础上增加   
  53.         rootSheet.setLoc(rootSheet.getDimsLoc());   
  54.         Map<Integer, Integer> map = new HashMap(10000);   
  55.         int sheetIndex = 0;   
  56.   
  57.         for (int i = 1; i < inputs.length; i++) { // 从第二篇开始遍历   
  58.             List<Record> records = getRecords(inputs[i]);   
  59.             // 达到最大行数限制,换一个sheet   
  60.             if (getRows(records) + rootRows >= RowRecord.MAX_ROW_NUMBER) {   
  61.                 if ((++sheetIndex) > (sheets.size() - 1)) {   
  62.                     logger.warn("第一个文档给出的sheets小于需要的数量,部分数据未能合并.");   
  63.                     break;   
  64.                 }   
  65.                 rootSheet = sheets.get(sheetIndex);   
  66.                 rootRows = getRowsOfSheet(rootSheet);   
  67.                 rootSheet.setLoc(rootSheet.getDimsLoc());   
  68.                 logger.debug("切换Sheet" + sheetIndex + "");   
  69.             }   
  70.             int rowsOfCurXls = 0;   
  71.             // 遍历当前文档的每一个record   
  72.             for (Iterator itr = records.iterator(); itr.hasNext();) {   
  73.                 Record record = (Record) itr.next();   
  74.                 if (record.getSid() == RowRecord.sid) { // 如果是RowRecord   
  75.                     RowRecord rowRecord = (RowRecord) record;   
  76.                     // 调整行号   
  77.                     rowRecord.setRowNumber(rootRows + rowRecord.getRowNumber());   
  78.                     rootSheet.addRow(rowRecord); // 追加Row   
  79.                     rowsOfCurXls++; // 记录当前文档的行数   
  80.                 }   
  81.                 // SST记录,SST保存xls文件中唯一的String,各个String都是对应着SST记录的索引   
  82.                 else if (record.getSid() == SSTRecord.sid) {   
  83.                     SSTRecord sstRecord = (SSTRecord) record;   
  84.                     for (int j = 0; j < sstRecord.getNumUniqueStrings(); j++) {   
  85.                         int index = workbook.addSSTString(sstRecord   
  86.                                 .getString(j));   
  87.                         // 记录原来的索引和现在的索引的对应关系   
  88.                         map.put(Integer.valueOf(j), Integer.valueOf(index));   
  89.                     }   
  90.                 } else if (record.getSid() == LabelSSTRecord.sid) {   
  91.                     LabelSSTRecord label = (LabelSSTRecord) record;   
  92.                     // 调整SST索引的对应关系   
  93.                     label.setSSTIndex(map.get(Integer.valueOf(label   
  94.                             .getSSTIndex())));   
  95.                 }   
  96.                 // 追加ValueCell   
  97.                 if (record instanceof CellValueRecordInterface) {   
  98.                     CellValueRecordInterface cell = (CellValueRecordInterface) record;   
  99.                     int cellRow = cell.getRow() + rootRows;   
  100.                     cell.setRow(cellRow);   
  101.                     rootSheet.addValueRecord(cellRow, cell);   
  102.                 }   
  103.             }   
  104.             rootRows += rowsOfCurXls;   
  105.         }   
  106.   
  107.         byte[] data = getBytes(workbook, sheets.toArray(new Sheet[0]));   
  108.         write(out, data);   
  109.     }   
  110.   
  111.     static void write(OutputStream out, byte[] data) {   
  112.         POIFSFileSystem fs = new POIFSFileSystem();   
  113.         // Write out the Workbook stream   
  114.         try {   
  115.             fs.createDocument(new ByteArrayInputStream(data), "Workbook");   
  116.             fs.writeFilesystem(out);   
  117.             out.flush();   
  118.         } catch (IOException e) {   
  119.             e.printStackTrace();   
  120.         } finally {   
  121.             try {   
  122.                 out.close();   
  123.             } catch (IOException e) {   
  124.                 e.printStackTrace();   
  125.             }   
  126.         }   
  127.     }   
  128.   
  129.     static List<Sheet> getSheets(Workbook workbook, List records) {   
  130.         int recOffset = workbook.getNumRecords();   
  131.         int sheetNum = 0;   
  132.   
  133.         // convert all LabelRecord records to LabelSSTRecord   
  134.         convertLabelRecords(records, recOffset, workbook);   
  135.         List<Sheet> sheets = new ArrayList();   
  136.         while (recOffset < records.size()) {   
  137.             Sheet sh = Sheet.createSheet(records, sheetNum++, recOffset);   
  138.   
  139.             recOffset = sh.getEofLoc() + 1;   
  140.             if (recOffset == 1) {   
  141.                 break;   
  142.             }   
  143.             sheets.add(sh);   
  144.         }   
  145.         return sheets;   
  146.     }   
  147.   
  148.     static int getRows(List<Record> records) {   
  149.         int row = 0;   
  150.         for (Iterator itr = records.iterator(); itr.hasNext();) {   
  151.             Record record = (Record) itr.next();   
  152.             if (record.getSid() == RowRecord.sid) {   
  153.                 row++;   
  154.             }   
  155.         }   
  156.         return row;   
  157.     }   
  158.   
  159.     static int getRowsOfSheet(Sheet sheet) {   
  160.         int rows = 0;   
  161.         sheet.setLoc(0);   
  162.         while (sheet.getNextRow() != null) {   
  163.             rows++;   
  164.         }   
  165.         return rows;   
  166.     }   
  167.   
  168.     @SuppressWarnings("deprecation")   
  169.     static List<Record> getRecords(InputStream input) {   
  170.         try {   
  171.             POIFSFileSystem poifs = new POIFSFileSystem(input);   
  172.             InputStream stream = poifs.getRoot().createDocumentInputStream(   
  173.                     "Workbook");   
  174.             return org.apache.poi.hssf.record.RecordFactory.createRecords(stream);   
  175.         } catch (IOException e) {   
  176.             logger.error("IO异常:" + e.getMessage() + "");   
  177.             e.printStackTrace();   
  178.         }   
  179.         return Collections.EMPTY_LIST;   
  180.     }   
  181.   
  182.     static void convertLabelRecords(List records, int offset, Workbook workbook) {   
  183.   
  184.         for (int k = offset; k < records.size(); k++) {   
  185.             Record rec = (Record) records.get(k);   
  186.   
  187.             if (rec.getSid() == LabelRecord.sid) {   
  188.                 LabelRecord oldrec = (LabelRecord) rec;   
  189.   
  190.                 records.remove(k);   
  191.                 LabelSSTRecord newrec = new LabelSSTRecord();   
  192.                 int stringid = workbook.addSSTString(new UnicodeString(oldrec   
  193.                         .getValue()));   
  194.   
  195.                 newrec.setRow(oldrec.getRow());   
  196.                 newrec.setColumn(oldrec.getColumn());   
  197.                 newrec.setXFIndex(oldrec.getXFIndex());   
  198.                 newrec.setSSTIndex(stringid);   
  199.                 records.add(k, newrec);   
  200.             }   
  201.         }   
  202.     }   
  203.   
  204.     public static byte[] getBytes(Workbook workbook, Sheet[] sheets) {   
  205.         // HSSFSheet[] sheets = getSheets();   
  206.         int nSheets = sheets.length;   
  207.   
  208.         // before getting the workbook size we must tell the sheets that   
  209.         // serialization is about to occur.   
  210.         for (int i = 0; i < nSheets; i++) {   
  211.             sheets[i].preSerialize();   
  212.         }   
  213.   
  214.         int totalsize = workbook.getSize();   
  215.         // pre-calculate all the sheet sizes and set BOF indexes   
  216.         int[] estimatedSheetSizes = new int[nSheets];   
  217.         for (int k = 0; k < nSheets; k++) {   
  218.             workbook.setSheetBof(k, totalsize);   
  219.             int sheetSize = sheets[k].getSize();   
  220.             estimatedSheetSizes[k] = sheetSize;   
  221.             totalsize += sheetSize;   
  222.         }   
  223.         logger.debug("分配内存" + totalsize + "bytes");   
  224.         byte[] retval = new byte[totalsize];   
  225.         int pos = workbook.serialize(0, retval);   
  226.         for (int k = 0; k < nSheets; k++) {   
  227.             int serializedSize = sheets[k].serialize(pos, retval);   
  228.             if (serializedSize != estimatedSheetSizes[k]) {   
  229.                 // Wrong offset values have been passed in the call to   
  230.                 // setSheetBof() above.   
  231.                 // For books with more than one sheet, this discrepancy would   
  232.                 // cause excel   
  233.                 // to report errors and loose data while reading the workbook   
  234.                 throw new IllegalStateException(   
  235.                         "Actual serialized sheet size (" + serializedSize   
  236.                                 + ") differs from pre-calculated size ("  
  237.                                 + estimatedSheetSizes[k] + ") for sheet (" + k   
  238.                                 + ")");   
  239.                 // write mis-aligned offsets either   
  240.             }   
  241.             pos += serializedSize;   
  242.         }   
  243.         return retval;   
  244.     }   
  245.   
  246. }  
分享到:
评论

相关推荐

    解决poi大数据量导出excel的代码

    解决poi大数据量导出excel的代码,该代码中所用的jar包是poi3.9。在测试过程中单个sheet中导出20万数据没有问题。

    java poi大数据量 导出excel

    java中使用poi导出Excel大批量数据 存在两个导出方法:存在一个分批量导出ZIP文件,一个导出exel文件

    java使用poi导出大量数据

    本篇文章将深入探讨如何利用POI高效地处理大数据量的导出。 首先,我们需要了解`DBUtil.java`和`LotExport.java`两个文件可能在项目中的作用。`DBUtil.java`通常包含了数据库操作的相关工具方法,比如连接数据库、...

    java poi导出大量数据到Excel

    1. **内存优化**:当数据量非常大时,建议使用Apache POI提供的SXSSF类来降低内存占用。 2. **性能考虑**:在实际应用中,应尽可能减少对Excel文件的读写操作,避免频繁创建和销毁对象。 3. **异常处理**:在处理...

    poi多线程大数据导出excel文件.zip

    在IT行业中,处理大数据量的Excel文件是一项挑战,特别是在数据导出时,如果单线程操作,可能会导致性能瓶颈和长时间的等待。Apache POI是一个流行的Java库,它允许开发者创建、修改和显示Microsoft Office格式的...

    使用POI导出大数据量到EXCEL

    "使用POI导出大数据量到EXCEL"这个主题涉及到如何高效地利用POI处理大量数据并将其导出到Excel文件中。以下是对这个主题的详细讲解。 1. **Apache POI简介** Apache POI 是一个开源项目,它提供了Java API来创建、...

    POI百万级大数据量EXCEL导出 - 请叫我猿叔叔的博客 - CSDN博客.htm

    POI百万级大数据量EXCEL导出 - 请叫我猿叔叔的博客 - CSDN博客.htm

    poi大量数据读取gc内存溢出解决方案

    poi读取大量数据会造成gc内存溢出的报错,由于垃圾回收机制无法将大量的对象及时的回收,而这些对象又会保存在内存中,会导致内存不够用的情况,这时候我们就需要使用新的方法,读取为cvs即可.此解决方案可支持千万数据的...

    springboot+mybatis+poi 实现excel导入导出

    - 导出:同样,先从数据库查询数据,转换为Excel所需的格式,再使用POI创建新的工作簿和工作表,填充数据,最后写入到OutputStream或者保存为文件。 ```java List&lt;Student&gt; students = studentMapper.selectAll()...

    POI实现的基于动态模板的EXCEL数据导出

    “大量数据导出”则强调了该方法适用于处理批量数据,比如用于报表生成、数据分析等场景。 从压缩包子文件的文件名称“excelExport”来看,这可能是包含主程序、模板文件或测试数据的文件夹,可能包含了示例模板、...

    Java利用POI实现数据Excel导出实例源码

    总的来说,Java结合Apache POI库实现Excel数据导出是企业级应用中常见的数据处理技术,能够有效地帮助用户处理大量数据,生成报表,或者进行数据交换。通过学习和实践这样的实例源码,开发者可以提高自己在文件操作...

    poi导出根据模板导出excel和简单列表导出excel源码

    大量数据导出时,一次性加载到内存可能导致内存溢出。为解决这个问题,可以采用流式处理(Streaming User Model)或分批处理。例如,使用SXSSF(Streaming Usermodel API)可以避免一次性加载所有数据,它会在磁盘...

    POI批量导入导出

    在导出方面,POI能够根据业务需求生成包含大量数据的Excel文件,可以自定义样式、颜色、字体等,使得导出的文件既实用又美观。在批量导出时,尤其适用于需要将数据库查询结果或者处理后的数据以Excel形式分发给用户...

    基于Apache POI导出大数据量(百万级)Excel的实现

    【作品名称】:基于Apache POI导出大数据量(百万级)Excel的实现 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:...

    数据库大量数据导出Excel

    其次,在实验过程中,大数据量的导出很容易引发内存溢出,调整JVM的内存大小治标不治本。很多人建议保存为.CSV格式的文件。不过,.CSV方式导出也存在问题:首先,如果用excel来打开csv,超过65536行的数据都会看不见...

    poi导出数据到excel里

    大量数据写入时,考虑使用`SXSSFWorkbook`,这是一个内存优化的版本,它允许以流式方式处理Excel文件,避免一次性加载整个文件到内存。 在提供的"ExcelUtil.java"文件中,可能包含了实现上述步骤的代码。通常,这...

    java excel大数据量导出demo,可支持模板导出

    在导出大数据量时,通过设置内存中的行数限制,可以有效防止内存溢出,同时保持较高的性能。 在"excelUtils"这个工具类中,我们可能会看到以下关键功能: 1. **模板导出**:用户可以预先定义Excel模板,包括单元格...

    基于poi的excel导入导出封装

    Apache POI是一个强大的Java库,专门用于处理Microsoft Office格式的文件,如Excel、Word和PowerPoint。在"基于poi的excel导入导出封装...通过学习和掌握Apache POI,你可以提高工作效率,处理大量数据变得更加便捷。

    JAVA实现数据库数据导入导出到Excel(POI)所需jar包

    在Java开发中,有时我们需要将数据库中的数据导出到Excel文件,或者从Excel文件导入数据到数据库。Apache POI是一个流行的API,专为处理Microsoft Office格式的文件,如Excel(.xlsx, .xls)。本教程将详细介绍如何...

    java-poi-excel-导出20万条记录【源代码】

    在Java开发中,处理大量数据导出到Excel文件是一个常见的需求,特别是在数据分析、报表生成或者数据备份等场景。本示例“java-poi-excel-导出20万条记录【源代码】”展示了如何使用Apache POI库来高效地处理大数据量...

Global site tag (gtag.js) - Google Analytics