`

POI导出大Excel问题

阅读更多

前段时间,做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: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileOutputStream; import java.io....

    POI导出 POI导出 POI导出

    POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI导出POI...

    springboot+poi导出指定格式Excel模板

    springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式...

    java使用POI导出 Excel工具类

    java使用POI导出 Excel+图片工具类 ,里面含有poi jar包,只调用接口即可直接保存Excel。使用的时候需先把数据封装,具体包装需根据实际导出数据进行处理。文件demo中只提供包装格式。

    struts2 poi导出到excel

    Struts2和Apache POI是Java开发中处理Web应用程序数据导出到Excel的常用工具。...以上就是使用Struts2和Apache POI导出数据到Excel的基本流程和关键知识点,实际应用中可能需要根据具体需求进行调整和优化。

    使用POI,实现excel文件导出,图片url导出文件,图片和excel文件导出压缩包

    使用POI导出Excel文件** 导出Excel文件主要涉及以下几个步骤: - **创建Workbook对象**:这是Excel文件的容器,可以使用`XSSFWorkbook`(针对.xlsx)或`HSSFWorkbook`(针对.xls)创建。 - **创建Sheet对象**:...

    使用poi方式导出excel(分多个sheet导出)

    七、导出Excel文件 最后,将Workbook写入OutputStream或File,完成导出: ```java try (FileOutputStream out = new FileOutputStream("output.xlsx")) { workbook.write(out); } catch (IOException e) { e....

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

    Apache POI 是一个开源项目,专门用于处理 Microsoft Office 格式的文件,如 Word、Excel 和 PowerPoint。...在实际项目中,这样的工具可以极大地提升开发效率,减少处理 Excel 文件时遇到的问题。

    POI导出Excel表格

    在这个“POI导出Excel表格”的实例中,我们将深入探讨如何利用Apache POI进行Excel文件的导入与导出操作。 首先,我们需要在项目中集成Apache POI库。如果你使用的是Maven,可以在pom.xml文件中添加以下依赖: ```...

    poi导出excel表格

    本教程将详细讲解如何使用Apache POI在Web环境中导出Excel表格,避免生成不必要的临时文件,从而优化系统资源管理。 一、Apache POI简介 Apache POI 是一个开源项目,它提供了Java API来处理Microsoft的Office格式...

    java poi导出excel

    以上就是使用Java POI导出Excel的基本步骤。你可以根据实际需求调整代码,例如添加数据遍历、样式设置、图表生成等功能。确保正确管理资源,避免内存泄漏,特别是在服务器端处理大量数据时。记得在完成后关闭工作簿...

    poi导出excel生成下拉列表

    poi作为导出excel常用的工具,方便快捷。对于excel指定下拉列表的列,如何生成呢?本文提供如何生成下拉列表的excel列

    POI的EXCEL导出,自动换行

    通过以上步骤,我们成功地实现了使用Apache POI在Java中导出Excel文件,并实现了自动换行的功能。这种方式不仅可以提高工作效率,还能确保数据的准确性和完整性。 #### 六、注意事项与优化建议 - **兼容性问题**:...

    POI导出操作Excel

    在这个例子中,我们看到如何使用POI库来将数据从数据库导出到Excel文件中。以下是关于这个话题的详细知识点: 1. **Apache POI**: Apache POI 是一个开源项目,它允许开发人员使用Java读取、写入和修改Microsoft ...

    java poi导出图片到excel示例代码

    Java POI导出图片到Excel示例代码详解 Java POI是Java开发中常用的开源库,用于读写Microsoft Office文件格式,包括Excel、Word、PowerPoint等。今天,我们将介绍如何使用Java POI将图片导出到Excel中。 标题解释 ...

    poi excel 模板读取并导出带公式的excel文档

    2. **通过模板导出Excel表格**: - 在开发中,通常会预先准备好一个Excel模板文件,这个模板文件包含了固定格式和一些基本的数据结构。 - Java程序通过读取这个模板文件,然后填充数据,最后将填充后的文件导出为...

    java poi导出大量数据到Excel

    保存并导出Excel文件 完成数据填充后,最后一步是关闭工作簿并将Excel文件保存到指定路径。根据给定代码示例,在保存之前还进行了文件路径的检查和创建操作。 ```java book.write(); book.close(); ``` #### 五、...

    poi 导出多表头

    在实际项目中,你可能会遇到性能优化的问题,因为 POI 直接操作内存模型可能导致内存消耗较大。为了解决这个问题,可以考虑使用SXSSFWorkbook,它允许以流式方式处理 Excel 文件,从而降低内存占用。 总之,利用 ...

    java_poi实现excel导入导出

    Java POI 实现 Excel 导入导出 Java POI 是一个流行的 Java 库,用于处理 Microsoft Office 文件格式,包括 Excel 文件。在本文中,我们将详细介绍如何使用 Java POI 实现 Excel 导入导出功能。 1. 什么是 Java ...

    poi导出excel需要的jar

    "poi导出excel需要的jar"指的是在使用Apache POI进行Excel导出时,你需要包含特定的JAR依赖文件。 首先,要实现POI导出Excel的功能,你需要下载Apache POI相关的JAR文件。这些文件通常包括以下核心组件: 1. **poi...

Global site tag (gtag.js) - Google Analytics