`
boys236
  • 浏览: 45717 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

解决大批量数据导出Excel产生内存溢出的方案(1)

阅读更多
  1. @SuppressWarnings("unchecked")   
  2. public class XlsMergeUtil {   
  3.   private static Logger logger = LoggerFactory.getLogger(XlsMergeUtil.class);   
  4.   
  5.   /**  
  6.    * 将多个Xls文件合并为一个,适用于只有一个sheet,并且格式相同的文档  
  7.    * @param inputs 输入的Xls文件  
  8.    * @param out 输出文件  
  9.    */  
  10.   public static void merge(InputStream[] inputs, OutputStream out) {   
  11.     if (inputs == null || inputs.length <= 1) {   
  12.       throw new IllegalArgumentException("没有传入输入流数组,或只有一个输入流.");   
  13.     }   
  14.   
  15.     List<Record> rootRecords = getRecords(inputs[0]);   
  16.     Workbook workbook = Workbook.createWorkbook(rootRecords);   
  17.     List<Sheet> sheets = getSheets(workbook, rootRecords);   
  18.     if(sheets == null || sheets.size() == 0) {   
  19.       throw new IllegalArgumentException("第一篇文档的格式错误,必须有至少一个sheet");   
  20.     }   
  21.     //以第一篇文档的最后一个sheet为根,以后的数据都追加在这个sheet后面   
  22.     Sheet rootSheet = sheets.get(sheets.size() - 1);    
  23.     int rootRows = getRowsOfSheet(rootSheet); //记录第一篇文档的行数,以后的行数在此基础上增加   
  24.     rootSheet.setLoc(rootSheet.getDimsLoc());   
  25.     Map<Integer, Integer> map = new HashMap(10000);   
  26.   
  27.     for (int i = 1; i < inputs.length; i++) { //从第二篇开始遍历   
  28.       List<Record> records = getRecords(inputs[i]);   
  29.       int rowsOfCurXls = 0;   
  30.       //遍历当前文档的每一个record   
  31.       for (Iterator itr = records.iterator(); itr.hasNext();) {   
  32.         Record record = (Record) itr.next();   
  33.         if (record.getSid() == RowRecord.sid) { //如果是RowRecord   
  34.           RowRecord rowRecord = (RowRecord) record;   
  35.           //调整行号   
  36.           rowRecord.setRowNumber(rootRows + rowRecord.getRowNumber());   
  37.           rootSheet.addRow(rowRecord); //追加Row   
  38.           rowsOfCurXls++; //记录当前文档的行数   
  39.         }   
  40.         //SST记录,SST保存xls文件中唯一的String,各个String都是对应着SST记录的索引   
  41.         else if (record.getSid() == SSTRecord.sid) {   
  42.           SSTRecord sstRecord = (SSTRecord) record;   
  43.           for (int j = 0; j < sstRecord.getNumUniqueStrings(); j++) {   
  44.             int index = workbook.addSSTString(sstRecord.getString(j));   
  45.             //记录原来的索引和现在的索引的对应关系   
  46.             map.put(Integer.valueOf(j), Integer.valueOf(index));   
  47.           }   
  48.         } else if (record.getSid() == LabelSSTRecord.sid) {   
  49.           LabelSSTRecord label = (LabelSSTRecord) record;   
  50.           //调整SST索引的对应关系   
  51.           label.setSSTIndex(map.get(Integer.valueOf(label.getSSTIndex())));   
  52.         }   
  53.         //追加ValueCell   
  54.         if (record instanceof CellValueRecordInterface) {   
  55.           CellValueRecordInterface cell = (CellValueRecordInterface) record;   
  56.           int cellRow = cell.getRow() + rootRows;   
  57.           cell.setRow(cellRow);   
  58.           rootSheet.addValueRecord(cellRow, cell);   
  59.         }   
  60.       }   
  61.       rootRows += rowsOfCurXls;   
  62.     }   
  63.     byte[] data = getBytes(workbook, sheets.toArray(new Sheet[0]));   
  64.     write(out, data);   
  65.   }   
  66.   
  67.   static void write(OutputStream out, byte[] data) {   
  68.     POIFSFileSystem fs = new POIFSFileSystem();   
  69.     // Write out the Workbook stream   
  70.     try {   
  71.       fs.createDocument(new ByteArrayInputStream(data), "Workbook");   
  72.       fs.writeFilesystem(out);   
  73.       out.flush();   
  74.     } catch (IOException e) {   
  75.       e.printStackTrace();   
  76.     } finally {   
  77.       try {   
  78.         out.close();   
  79.       } catch (IOException e) {   
  80.         e.printStackTrace();   
  81.       }   
  82.     }   
  83.   }   
  84.   
  85.   static List<Sheet> getSheets(Workbook workbook, List records) {   
  86.     int recOffset = workbook.getNumRecords();   
  87.     int sheetNum = 0;   
  88.   
  89.     // convert all LabelRecord records to LabelSSTRecord   
  90.     convertLabelRecords(records, recOffset, workbook);   
  91.     List<Sheet> sheets = new ArrayList();   
  92.     while (recOffset < records.size()) {   
  93.       Sheet sh = Sheet.createSheet(records, sheetNum++, recOffset);   
  94.   
  95.       recOffset = sh.getEofLoc() + 1;   
  96.       if (recOffset == 1) {   
  97.         break;   
  98.       }   
  99.       sheets.add(sh);   
  100.     }   
  101.     return sheets;   
  102.   }   
  103.   
  104.   static int getRows(List<Record> records) {   
  105.     int row = 0;   
  106.     for (Iterator itr = records.iterator(); itr.hasNext();) {   
  107.       Record record = (Record) itr.next();   
  108.       if (record.getSid() == RowRecord.sid) {   
  109.         row++;   
  110.       }   
  111.     }   
  112.     return row;   
  113.   }   
  114.      
  115.   static int getRowsOfSheet(Sheet sheet) {   
  116.     int rows = 0;   
  117.     sheet.setLoc(0);   
  118.     while(sheet.getNextRow() != null) {   
  119.       rows++;   
  120.     }   
  121.     return rows;   
  122.   }   
  123.   
  124.   @SuppressWarnings("deprecation")   
  125.   static List<Record> getRecords(InputStream input) {   
  126.     try {   
  127.       POIFSFileSystem poifs = new POIFSFileSystem(input);   
  128.       InputStream stream = poifs.getRoot().createDocumentInputStream("Workbook");   
  129.       return org.apache.poi.hssf.record.RecordFactory.createRecords(stream);   
  130.     } catch (IOException e) {   
  131.       logger.error("IO异常:{}", e.getMessage());   
  132.       e.printStackTrace();   
  133.     }   
  134.     return Collections.EMPTY_LIST;   
  135.   }   
  136.   
  137.   static void convertLabelRecords(List records, int offset, Workbook workbook) {   
  138.   
  139.     for (int k = offset; k < records.size(); k++) {   
  140.       Record rec = (Record) records.get(k);   
  141.   
  142.       if (rec.getSid() == LabelRecord.sid) {   
  143.         LabelRecord oldrec = (LabelRecord) rec;   
  144.   
  145.         records.remove(k);   
  146.         LabelSSTRecord newrec = new LabelSSTRecord();   
  147.         int stringid = workbook.addSSTString(new UnicodeString(oldrec.getValue()));   
  148.   
  149.         newrec.setRow(oldrec.getRow());   
  150.         newrec.setColumn(oldrec.getColumn());   
  151.         newrec.setXFIndex(oldrec.getXFIndex());   
  152.         newrec.setSSTIndex(stringid);   
  153.         records.add(k, newrec);   
  154.       }   
  155.     }   
  156.   }   
  157.   
  158.   public static byte[] getBytes(Workbook workbook, Sheet[] sheets) {   
  159.     // HSSFSheet[] sheets = getSheets();   
  160.     int nSheets = sheets.length;   
  161.   
  162.     // before getting the workbook size we must tell the sheets that   
  163.     // serialization is about to occur.   
  164.     for (int i = 0; i < nSheets; i++) {   
  165.       sheets[i].preSerialize();   
  166.     }   
  167.   
  168.     int totalsize = workbook.getSize();   
  169.   
  170.     // pre-calculate all the sheet sizes and set BOF indexes   
  171.     int[] estimatedSheetSizes = new int[nSheets];   
  172.     for (int k = 0; k < nSheets; k++) {   
  173.       workbook.setSheetBof(k, totalsize);   
  174.       int sheetSize = sheets[k].getSize();   
  175.       estimatedSheetSizes[k] = sheetSize;   
  176.       totalsize += sheetSize;   
  177.     }   
  178.   
  179.     byte[] retval = new byte[totalsize];   
  180.     int pos = workbook.serialize(0, retval);   
  181.   
  182.     for (int k = 0; k < nSheets; k++) {   
  183.       int serializedSize = sheets[k].serialize(pos, retval);   
  184.       if (serializedSize != estimatedSheetSizes[k]) {   
  185.             throw new IllegalStateException("Actual serialized sheet size (" + serializedSize   
  186.             + ") differs from pre-calculated size (" + estimatedSheetSizes[k] + ") for sheet (" + k   
  187.             + ")");   
  188.         Sheet.serializeIndexRecord() does not   
  189.       }   
  190.       pos += serializedSize;   
  191.     }   
  192.     return retval;   
  193.   }   
  194.   
  195.   public static void main(String[] args) throws Exception {   
  196.     final String PATH = "E:\\projects\\java\\ws_0\\export\\data\\";   
  197.     InputStream[] inputs = new InputStream[10];   
  198.     inputs[0] = new java.io.FileInputStream(PATH + "07_10.xls");   
  199.     for(int i = 1; i <= 9; i++) {   
  200.       inputs[i] = new java.io.FileInputStream(PATH + "07_0" + i + ".xls");   
  201.     }   
  202.     OutputStream out = new FileOutputStream(PATH + "xx.xls");   
  203.     long t1 = System.currentTimeMillis();   
  204.     merge(inputs, out);   
  205.     System.out.println(System.currentTimeMillis() - t1);//简陋的测试一下时间   
  206.   }   
  207.   
  208. }  
分享到:
评论

相关推荐

    java解决大批量数据导出Excel产生内存溢出的方案

    在Java开发中,当面临大批量数据导出到Excel文件时,可能会遇到内存溢出的问题。这是因为Excel文件格式本身的设计,以及Java默认处理大数据的方式,可能导致内存占用过高,尤其是在一次性加载大量数据到内存中进行...

    java导出30万数据量的excel(采用生成多个excel,最后打包zip)

    在Java开发中,处理大数据量的Excel导出是一项常见的任务,尤其当数据量达到数十万条时,单个Excel文件可能会遇到性能瓶颈或格式限制。本项目针对这一问题提出了一种解决方案,即分块生成多个Excel文件,然后将它们...

    大批量excel导出下载

    这个标题和描述提到的是一个针对批量导出Excel的工具类,它包括了两个核心类:`ExcelReader.java` 和 `ExcelWriter.java`,以及关于大批量导出的解决方案。下面将详细解释这些知识点。 1. **ExcelReader.java**: 这...

    java多线程导出excel(千万级别)优化

    Java多线程导出Excel是处理大数据量时的一种高效策略,尤其在面对千万级别的数据时。传统的Apache POI库在处理大规模数据时可能会遇到栈溢出(StackOverflowError)和内存溢出(OutOfMemoryError)等问题,因为这些...

    java中使用poi导出Excel大批量数据到客户端

    在java web系统应用中我们经常会用到大批量数据的导出,动辄就上几十万几百万的数据让我们的程序感觉压力很大,甚至都出现无法导出的情况,如内存溢出等。 java中使用poi导出Excel大批量数据到客户端 存在两个导出...

    easyExcel实现大数据导出

    `easyExcel`是专门为处理大量数据设计的一个轻量级工具,它能够有效地解决内存溢出问题,特别适合大数据量的Excel读写操作。下面将详细阐述`easyExcel`的核心功能、使用方法以及如何实现大数据导出。 `easyExcel`的...

    poi_模板导出excel,支持百万级数据模板导出

    poi导入、导出,支持百万级数据模板导出、合并excel。项目为spring-boot-2上开发。resource里面有模板,在junit...注意此版本不支持分页导出,一次性导出大批量数据也会出现内存溢出问题,最新上传的版本支持分页导出,

    Excel大批量导入导出解决方案.docx

    ### Excel大批量导入导出解决方案 #### 概述 在处理大规模Excel文件的过程中,经常会遇到内存溢出或者频繁Full Garbage Collection (FGC)的问题,这些问题通常与Java中使用Apache POI库操作Excel文件的方式有关。...

    java实现csv导出千万级数据实例

    本实例聚焦于“java实现csv导出千万级数据实例”,旨在提供一个高效、稳定的解决方案,避免因数据量过大而导致的性能问题,如Java中的栈溢出(Stack Overflow)。CSV(Comma Separated Values)格式因其简单、通用性...

    CSV大数据分批并压缩导出

    总的来说,CSV大数据分批并压缩导出是一种实用且高效的解决方案,特别适用于需要处理海量数据且内存资源有限的环境。它结合了分批处理的内存管理策略和压缩技术的空间优化,确保了大数据操作的可行性和性能。

    [rar文件] java导出100万以上excel大数据样例

    1、 大数据导出excel文件; 2、 Excel导出大数据时内存溢出; 二、思路:将数据存储到一个.xls的文件内,实际写入的是可以通过excel打开的html文本文件。由于文本文件可以进行续写,可以避免内存溢出。 三、优点:...

    真香!Java 导出 Excel 表格竟变得如此简单优雅

    poi 和 jxl 对内存的消耗很大,在处理大批量的数据时,容易造成内存溢出。比如处理一个 3M 的 Excel,poi 和 jxl 可能需要上百兆的内存,但 easyexcel 可能只需要几百或几千 KB(内存消耗对比有些夸张)。在性能这...

    Android-Android使用jxl快速导出excel表

    本文将详细探讨如何在Android应用中使用jxl库快速导出Excel表格。 首先,我们需要理解jxl库的基本概念。jxl是一个Java API,它支持Microsoft Excel 97-2004的文件格式(.xls)。通过jxl,我们可以创建新的工作簿、...

    Java使用POI导出大数据量Excel的方法

    在Java开发中,导出大数据量的Excel文件可能会面临内存溢出的问题,特别是在使用Apache POI库时。这是因为默认情况下,POI会将整个Excel工作簿存储在内存中,当数据量过大时,内存消耗非常显著,可能导致系统崩溃。...

    excel java中导入导出

    博文链接提供的资源“数据大批量导出(有代码有真相).docx”可能包含具体的示例代码和实践案例,可以作为学习和参考的依据。通过深入研究这些示例,开发者能够更好地掌握如何在Java中高效地进行Excel文件的导入导出。

    Java实现excel大数据量导入

    Java实现Excel大数据量导入是一项常见的任务,特别是在处理企业级数据导入导出时。Apache POI 是Java中广泛使用的库,用于处理Microsoft Office格式的文件,包括Excel。然而,当涉及大量数据时,直接使用POI的用户...

    NPOI 2.0 DLL文件

    3. **大批量数据导出**:对于大数据量的应用场景,NPOI能有效地处理和导出大量数据,通过优化内存管理和流式处理,避免了内存溢出问题。这对于需要快速生成报表或分析结果的系统来说,是非常有用的。 4. **跨平台...

    alibaba easyexcel

    2. **性能卓越**:通过优化的数据解析和生成机制,EasyExcel在读写速度上表现出色,尤其适合处理大批量数据的导入导出操作。 3. **简单易用**:EasyExcel的API设计简洁,提供了丰富的注解和模板,使得开发者可以...

Global site tag (gtag.js) - Google Analytics