`

Java处理大量数据到Excel

阅读更多
本人尝试用了JXL, POI3.2到3.8版本按照一般的方式来生出大量的数据到Excel,例如100000条数据,基本上都会出现OOM的情况。

下面的例子给我们介绍POI是怎么处理大量数据写到EXCEL里面的:

/* ====================================================================
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
==================================================================== */

package org.apache.poi.xssf.usermodel.examples;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.*;

/**
* Demonstrates a workaround you can use to generate large workbooks and avoid OutOfMemory exception.
*
* The trick is as follows:
* 1. create a template workbook, create sheets and global objects such as cell styles, number formats, etc.
* 2. create an application that streams data in a text file
* 3. Substitute the sheet in the template with the generated data
*
* <p>
*      Since 3.8-beta3 POI provides a low-memory footprint SXSSF API which implementing the "BigGridDemo" strategy.
*      XSSF is an API-compatible streaming extension of XSSF to be used when
*      very large spreadsheets have to be produced, and heap space is limited.
*      SXSSF achieves its low memory footprint by limiting access to the rows that
*      are within a sliding window, while XSSF gives access to all rows in the
*      document. Older rows that are no longer in the window become inaccessible,
*      as they are written to the disk.
* </p>
* See <a "http://poi.apache.org/spreadsheet/how-to.html#sxssf">
*     http://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.

*
* @author Yegor Kozlov
*/
public class BigGridDemo {
    private static final String XML_ENCODING = "UTF-8";
   
    public static void main(String[] args) throws Exception {

        // Step 1. Create a template file. Setup sheets and workbook-level objects such as
        // cell styles, number formats, etc.

        XSSFWorkbook wb = new XSSFWorkbook();
        XSSFSheet sheet = wb.createSheet("Big Grid");

        Map<String, XSSFCellStyle> styles = createStyles(wb);
        //name of the zip entry holding sheet data, e.g. /xl/worksheets/sheet1.xml
        String sheetRef = sheet.getPackagePart().getPartName().getName();

        //save the template
        FileOutputStream os = new FileOutputStream("template.xlsx");
        wb.write(os);
        os.close();

        //Step 2. Generate XML file.
        File tmp = File.createTempFile("sheet", ".xml");
        Writer fw = new OutputStreamWriter(new FileOutputStream(tmp), XML_ENCODING);
        generate(fw, styles);
        fw.close();

        //Step 3. Substitute the template entry with the generated data
        FileOutputStream out = new FileOutputStream("big-grid.xlsx");
        substitute(new File("template.xlsx"), tmp, sheetRef.substring(1), out);
        out.close();
    }

    /**
     * Create a library of cell styles.
     */
    private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
        Map<String, XSSFCellStyle> styles = new HashMap<String, XSSFCellStyle>();
        XSSFDataFormat fmt = wb.createDataFormat();

        XSSFCellStyle style1 = wb.createCellStyle();
        style1.setAlignment(XSSFCellStyle.ALIGN_RIGHT);
        style1.setDataFormat(fmt.getFormat("0.0%"));
        styles.put("percent", style1);

        XSSFCellStyle style2 = wb.createCellStyle();
        style2.setAlignment(XSSFCellStyle.ALIGN_CENTER);
        style2.setDataFormat(fmt.getFormat("0.0X"));
        styles.put("coeff", style2);

        XSSFCellStyle style3 = wb.createCellStyle();
        style3.setAlignment(XSSFCellStyle.ALIGN_RIGHT);
        style3.setDataFormat(fmt.getFormat("$#,##0.00"));
        styles.put("currency", style3);

        XSSFCellStyle style4 = wb.createCellStyle();
        style4.setAlignment(XSSFCellStyle.ALIGN_RIGHT);
        style4.setDataFormat(fmt.getFormat("mmm dd"));
        styles.put("date", style4);

        XSSFCellStyle style5 = wb.createCellStyle();
        XSSFFont headerFont = wb.createFont();
        headerFont.setBold(true);
        style5.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style5.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
        style5.setFont(headerFont);
        styles.put("header", style5);

        return styles;
    }

    private static void generate(Writer out, Map<String, XSSFCellStyle> styles) throws Exception {

        Random rnd = new Random();
        Calendar calendar = Calendar.getInstance();

        SpreadsheetWriter sw = new SpreadsheetWriter(out);
        sw.beginSheet();

        //insert header row
        sw.insertRow(0);
        int styleIndex = styles.get("header").getIndex();
        sw.createCell(0, "Title", styleIndex);
        sw.createCell(1, "% Change", styleIndex);
        sw.createCell(2, "Ratio", styleIndex);
        sw.createCell(3, "Expenses", styleIndex);
        sw.createCell(4, "Date", styleIndex);

        sw.endRow();

        //write data rows
        for (int rownum = 1; rownum < 100000; rownum++) {
            sw.insertRow(rownum);

            sw.createCell(0, "Hello, " + rownum + "!");
            sw.createCell(1, (double)rnd.nextInt(100)/100, styles.get("percent").getIndex());
            sw.createCell(2, (double)rnd.nextInt(10)/10, styles.get("coeff").getIndex());
            sw.createCell(3, rnd.nextInt(10000), styles.get("currency").getIndex());
            sw.createCell(4, calendar, styles.get("date").getIndex());

            sw.endRow();

            calendar.roll(Calendar.DAY_OF_YEAR, 1);
        }
        sw.endSheet();
    }

    /**
     *
     * @param zipfile the template file
     * @param tmpfile the XML file with the sheet data
     * @param entry the name of the sheet entry to substitute, e.g. xl/worksheets/sheet1.xml
     * @param out the stream to write the result to
     */
private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
        ZipFile zip = new ZipFile(zipfile);

        ZipOutputStream zos = new ZipOutputStream(out);

        @SuppressWarnings("unchecked")
        Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();
        while (en.hasMoreElements()) {
            ZipEntry ze = en.nextElement();
            if(!ze.getName().equals(entry)){
                zos.putNextEntry(new ZipEntry(ze.getName()));
                InputStream is = zip.getInputStream(ze);
                copyStream(is, zos);
                is.close();
            }
        }
        zos.putNextEntry(new ZipEntry(entry));
        InputStream is = new FileInputStream(tmpfile);
        copyStream(is, zos);
        is.close();

        zos.close();
    }

    private static void copyStream(InputStream in, OutputStream out) throws IOException {
        byte[] chunk = new byte[1024];
        int count;
        while ((count = in.read(chunk)) >=0 ) {
          out.write(chunk,0,count);
        }
    }

    /**
     * Writes spreadsheet data in a Writer.
     * (YK: in future it may evolve in a full-featured API for streaming data in Excel)
     */
    public static class SpreadsheetWriter {
        private final Writer _out;
        private int _rownum;

        public SpreadsheetWriter(Writer out){
            _out = out;
        }

        public void beginSheet() throws IOException {
            _out.write("<?xml version=\"1.0\" encoding=\""+XML_ENCODING+"\"?>" +
                    "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" );
            _out.write("<sheetData>\n");
        }

        public void endSheet() throws IOException {
            _out.write("</sheetData>");
            _out.write("</worksheet>");
        }

        /**
         * Insert a new row
         *
         * @param rownum 0-based row number
         */
        public void insertRow(int rownum) throws IOException {
            _out.write("<row r=\""+(rownum+1)+"\">\n");
            this._rownum = rownum;
        }

        /**
         * Insert row end marker
         */
        public void endRow() throws IOException {
            _out.write("</row>\n");
        }

        public void createCell(int columnIndex, String value, int styleIndex) throws IOException {
            String ref = new CellReference(_rownum, columnIndex).formatAsString();
            _out.write("<c r=\""+ref+"\" t=\"inlineStr\"");
            if(styleIndex != -1) _out.write(" s=\""+styleIndex+"\"");
            _out.write(">");
            _out.write("<is><t>"+value+"</t></is>");
            _out.write("</c>");
        }

        public void createCell(int columnIndex, String value) throws IOException {
            createCell(columnIndex, value, -1);
        }

        public void createCell(int columnIndex, double value, int styleIndex) throws IOException {
            String ref = new CellReference(_rownum, columnIndex).formatAsString();
            _out.write("<c r=\""+ref+"\" t=\"n\"");
            if(styleIndex != -1) _out.write(" s=\""+styleIndex+"\"");
            _out.write(">");
            _out.write("<v>"+value+"</v>");
            _out.write("</c>");
        }

        public void createCell(int columnIndex, double value) throws IOException {
            createCell(columnIndex, value, -1);
        }

        public void createCell(int columnIndex, Calendar value, int styleIndex) throws IOException {
            createCell(columnIndex, DateUtil.getExcelDate(value, false), styleIndex);
        }
    }
}
分享到:
评论

相关推荐

    Java解析大数据量Excel,可解析1048576行excel

    在处理大数据量的Excel文件时,Java是一种常用的语言,因为它提供了强大的库,如Apache POI,使得解析大型Excel文件成为可能。Apache POI是Java的一个开源项目,专门用于读写Microsoft Office格式的文件,包括Excel...

    java poi导出大量数据到Excel

    ### Java POI 大量数据导出到Excel详解 #### 一、背景介绍 在日常工作中,经常需要处理大量的数据并将其导出为Excel文件,特别是在金融、电商等行业。Java POI库作为一款强大的用于读写Microsoft Office文档的Java ...

    java Excel导出 Excel数据处理

    在实际项目中,你可能需要处理大量数据,这时性能优化就很重要。例如,可以使用SXSSF(Streaming Usermodel API)作为POI的一个子项目,它允许以内存最小化的方式处理大型Excel文件。 此外,如果你需要进行更复杂的...

    java poi 导入大数据量Excel数据 防止内存溢出处理.zip

    然而,当处理大数据量的Excel文件时,POI可能会导致内存溢出(Out of Memory, OOM),因为默认情况下它会将整个工作簿加载到内存中。为了防止这种问题,我们需要采用优化策略来高效地处理大量数据。 1. **分块读取*...

    java动态大数据量EXCEL下载

    传统的Java Excel库,如Apache POI,虽然功能强大,但在处理大量数据时可能会遇到性能瓶颈,因为它们会将整个Excel文件加载到内存中。为了解决这个问题,可以使用一些优化策略,比如分块读写,只处理当前需要的部分...

    Java处理100万行超大Excel文件秒级响应

    通过使用EasyExcel,我们不仅解决了处理大量Excel数据时可能出现的内存溢出问题,还大大提高了数据处理的速度。对于104万行20列的大规模Excel文件,EasyExcel能够在70秒内完成处理,极大地提高了工作效率。未来,...

    Java导出数据到Excel文件中(支持多表头)

    在代码实现中,我们需要创建一个`SXSSFWorkbook`对象,它是一个内存优化的Excel工作簿,可以处理大量数据。接着,我们创建`SXSSFSheet`作为工作簿中的工作表,并设置表头。一级表头可以通过`createRow`方法创建行并...

    java导出数据到Excel

    如果处理大量数据,记得使用SXSSFWorkbook,它提供了流式写入,可以显著提高性能并减少内存占用。 8. **处理日期和数字** 对于日期和数字,需要设置相应的数据类型,否则默认会被识别为字符串: ```java cell....

    java 处理Excel 带 List

    在实际项目中,可能还需要考虑性能问题,因为处理大量数据时,内存消耗可能会很大。为了解决这个问题,可以使用SXSSF(Streaming Usermodel API)作为替代,它允许以流式方式处理Excel,从而减少内存占用。 总结来...

    java实现数据导出到Excel

    此外,如果你的数据来自数据库或其他数据源,你可能需要使用迭代器来高效地读取和写入大量数据,以避免内存溢出。Apache POI提供了流式处理API,如SXSSFWorkbook,可以在内存有限的情况下处理大型数据集。 在SSH...

    java实现Excel数据导入到数据库

    例如,可以将Excel文件按行分块处理,或者在导入大量数据时使用批量插入。 总之,Java结合Apache POI和JDBC提供了一套完整的解决方案,用于在Excel和MySQL数据库之间进行数据迁移。通过熟练掌握这些工具和技术,...

    java导出到excel的工具类

    2. 提供数据分页功能,避免一次性加载大量数据导致内存溢出。 3. 增加列标题的设置,使导出的Excel文件更易于理解。 4. 添加数据验证和错误处理,确保输入数据的正确性。 5. 支持多sheet导出,方便组织复杂的Excel...

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

    这是因为Excel文件格式本身的设计,以及Java默认处理大数据的方式,可能导致内存占用过高,尤其是在一次性加载大量数据到内存中进行处理时。为了解决这个问题,我们可以采用以下几种策略: 1. **分批导出**: - ...

    Java数据导出到Excel模板

    - **内存管理**:大量数据可能导致内存溢出,需注意合理分批处理或使用SXSSFWorkbook(提供流式写入,减少内存占用)。 - **样式设置**:可以创建并应用自定义样式,如字体、颜色、边框等,以提升导出文件的美观度...

    java Excel上传 Excel数据处理

    7. **批量操作**:如果需要对大量数据进行操作,可以考虑分批读取和处理,而不是一次性加载所有数据。此外,使用多线程可以进一步提高处理速度。 8. **返回结果**:处理完成后,可能需要将结果反馈给用户,例如通过...

    Java+MySQL+将数据导入到Excel中,Java将Excel中的数据导入到MySQL数据库中,

    在处理大量数据时,Excel作为一种便捷的数据分析工具,经常被用于数据的整理和预处理。本主题主要涉及如何使用Java通过Apache POI库操作Excel文件,并将数据导入到MySQL数据库中,以及反向操作,即从数据库中提取...

    JAVA导出数据到excel中大数据量的解决方法

    web项目中需要有将数据导出excel的操作需求 使用html格式导出方法,但在...待所有数据写完,将各个小excel文件进行打包,输出到输出流中。 一小部分说明 见 http://blog.csdn.net/lisen1987/article/details/16857359

    java中,list集合数据导出到excel表格通用工具类

    在Java编程中,将List集合数据导出到Excel表格是一个常见的需求,特别是在数据分析、报表生成或数据...在处理大量数据时,这种通用化的方法尤其有价值,因为它允许快速地将任何符合特定格式的对象集合转化为Excel文件。

    java中将数据和图片导出到Excel文件

    在Java编程环境下实现数据及图片导出至Excel文件是一项常见的任务,特别是在处理报表、数据分析等场景时。本文将详细解析如何通过Java代码来完成这一过程,包括如何创建Excel文档、写入数据、插入图片等关键步骤。 ...

Global site tag (gtag.js) - Google Analytics