java poi 写入大量数据到excel中

  最近在利用poi往excel中写入大量数据时,发现excel2003最多只支持65535条,大量数据时容易造成oom,上网查了一下api,发现目前对于2003,每个sheet最多支持65535条,若数据量远超65535,建议分sheet处理,而poi3.8之后,出现了SXSSFWorkbook,可以支持大数据量的写入excel操作,但是目前只支持excel2007

HSSF是POI工程对Excel 97(-2007)文件操作的纯Java实现
XSSF是POI工程对Excel 2007 OOXML (.xlsx)文件操作的纯Java实现

从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的API----SXSSF

SXSSF通过一个滑动窗口来限制访问Row的数量从而达到低内存占用的目录,XSSF可以访问所有行。旧的行数据不再出现在滑动窗口中并变得无法访问,与此同时写到磁盘上。
在自动刷新的模式下,可以指定窗口中访问Row的数量,从而在内存中保持一定数量的Row。当达到这一数量时,在窗口中产生新的Row数据,并将低索引的数据从窗口中移动到磁盘中。
或者,滑动窗口的行数可以设定成自动增长的。它可以根据需要周期的根据一次明确的flushRow(int keepRows)调用来进行修改。

SXSSF (Streaming Usermodel API)

SXSSF (package: org.apache.poi.xssf.streaming) 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.

You can specify the window size at workbook construction time via new SXSSFWorkbook(int windowSize) or you can set it per-sheet via SXSSFSheet#setRandomAccessWindowSize(int windowSize)

When a new row is created via createRow() and the total number of unflushed records would exceed the specified window size, then the row with the lowest index value is flushed and cannot be accessed via getRow() anymore.

The default window size is 100 and defined by SXSSFWorkbook.DEFAULT_WINDOW_SIZE.

A windowSize of -1 indicates unlimited access. In this case all records that have not been flushed by a call to flushRows() are available for random access.

Note that SXSSF allocates temporary files that you must always clean up explicitly, by calling the dispose method.

SXSSFWorkbook defaults to using inline strings instead of a shared strings table. This is very efficient, since no document content needs to be kept in memory, but is also known to produce documents that are incompatible with some clients. With shared strings enabled all unique strings in the document has to be kept in memory. Depending on your document content this could use a lot more resources than with shared strings disabled.

Carefully review your memory budget and compatibility needs before deciding whether to enable shared strings or not.

The example below writes a sheet with a window of 100 rows. When the row count reaches 101, the row with rownum=0 is flushed to disk and removed from memory, when rownum reaches 102 then the row with rownum=1 is flushed, etc.

import junit.framework.Assert;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

    public static void main(String[] args) throws Throwable {
        SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
        Sheet sh = wb.createSheet();
        for(int rownum = 0; rownum < 1000; 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);
            }

        }

        // Rows with rownum < 900 are flushed and not accessible
        for(int rownum = 0; rownum < 900; rownum++){
          Assert.assertNull(sh.getRow(rownum));//调用了getRow方法,写入到磁盘中,释放了内存
        }

        // ther last 100 rows are still in memory
        for(int rownum = 900; rownum < 1000; rownum++){
           // Assert.assertNotNull(sh.getRow(rownum));//未调用,保留在内存中
        }

        FileOutputStream out = new FileOutputStream("D:\\sxssf.xlsx");
        wb.write(out);
        out.close();

        // dispose of temporary files backing this workbook on disk
        wb.dispose();
    }

The next example turns off auto-flushing (windowSize=-1) and the code manually controls how portions of data are written to disk

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

    public static void main(String[] args) throws Throwable {
        SXSSFWorkbook wb = new SXSSFWorkbook(-1); // turn off auto-flushing and accumulate all rows in memory
        Sheet sh = wb.createSheet();
        for(int rownum = 0; rownum < 1000; 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);
            }

           // manually control how rows are flushed to disk
           if(rownum % 100 == 0) {
                ((SXSSFSheet)sh).flushRows(100); // retain 100 last rows and flush all others

                // ((SXSSFSheet)sh).flushRows() is a shortcut for ((SXSSFSheet)sh).flushRows(0),
                // this method flushes all rows
           }

        }

        FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
        wb.write(out);
        out.close();

        // dispose of temporary files backing this workbook on disk
        wb.dispose();
   }

SXSSF flushes sheet data in temporary files (a temp file per sheet) and the size of these temporary files can grow to a very large value. For example, for a 20 MB csv data the size of the temp xml becomes more than a gigabyte. If the size of the temp files is an issue, you can tell SXSSF to use gzip compression:

  SXSSFWorkbook wb = new SXSSFWorkbook();
  wb.setCompressTempFiles(true); // temp files will be gzipped

以上内容来自API及个人总结,详见源API    http://poi.apache.org/spreadsheet/how-to.html
时间: 2024-10-10 21:40:29

java poi 写入大量数据到excel中的相关文章

java POI 写入百万数据到 excel

.xls文件只支持6w+的数据写入 .xlsx文件只支持104w+数据的写入 在java中jxl工具类只能操作.xls的文件,不能操作.xlsx的文件 POI工具类能够支持.xlsx的文件操作. excel的数据读写都相应的简单,网上也有很多的代码,我这里要说的是怎么样写入100w+的数据到Excel中. 在POI中,XSSFWorkbook  wb = new XSSFWorkbook ();创建的工作簿能够写入大量的数据,但很大的可能下会虚拟机内存不够而报错 在这种情况下有两种解决方案: 1

使用poi导出大量数据到excel遇到的问题

最近在工作遇到利用poi导出大量数据到excel并提供下载的运用场景,并遇到了一个问题,当数据量过大时(几十万),后台在进行数据写入excel中的过程会非常耗时,导致迟迟没有响应前台,结果数据还没导完,前台页面就已经崩掉了. 解决思路:接收到前台导出excel请求之后,开一个线程,在线程里进行数据的写入和将写入完成的excel保存到服务器中等耗时操作,前台定时发送ajax请求检测是否已经导出完成,如果完成则提供一个下载链接到前台供用户下载. 想到解决思路之后,自己写了一个小demo,顺便学习下利

C#将SQL数据库中数据导入Excel中,并将Excel中反导入SQL数据库中

实际的开发中,我们会经常遇到数据的转化的需要,将Excel中的数据转入到SQL中,或将SQL在数据库表中的数据导入到Excel中.代码如下: Code using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windo

c# winform DataGridView导出数据到Excel中,可以导出当前页和全部数据

准备工作就是可以分页的DataGridView,和两个按钮,一个用来导出当前页数据到Excel,一个用来导出全部数据到Excel 没有使用SaveFileDialog,但却可以弹出保存对话框来 先做导出当前页数据到Excel的 DataGridView命名为dataGridView1 1 //按下导出按钮 2 private void button7_Click(object sender, EventArgs e) 3 { 4 print(dataGridView1); 5 } 6 publi

POI读写大数据量excel,解决超过几万行而导致内存溢出的问题

1. Excel2003与Excel2007 两个版本的最大行数和列数不同,2003版最大行数是65536行,最大列数是256列,2007版及以后的版本最大行数是1048576行,最大列数是16384列. excel2003是以二进制的方式存储,这种格式不易被其他软件读取使用:而excel2007采用了基于XML的ooxml开放文档标准,ooxml使用XML和ZIP技术结合进行文件存储,XML是一个基于文本的格式,而且ZIP容器支持内容的压缩,所以其一大优势是可以大大减小文件的尺寸. 2. 大批

Java实现Oracle导出数据到Excel

1.导入相应的jar包(jxl.jar 和 数据库连接的jar包) 2.写数据库连接的工具类 import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException; public class Dbutil {    /*     * 功能:编写一个静态方法用于与数据库建立连接 输入参数:无 返回值:数据库连接对象     */ 

POI 导出大批量数据的Excel

POI作为操作Excel的三方库应用广泛,本文着重讨论导出大批量数据的Excel的处理,版本为4.1.0: <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.0</version> </dependency> 使用HSSFWorkbook进行导出,示例代码如下,代码中导出5万行20列的

SqlServer表数据与excel中数据的互相复制

一.SqlServer表数据复制到excel 1.新建查询,用sql语句把表数据读出来 2.然后,选择数据,右键,复制(也可以点击连同标题复制),复制到记事本中(不然会乱码) 3.然后再把记事本的内容复制,在excel中粘贴就可以了. 二.excel复制到SqlServer表数据 1.打开excel复制数据. 2.用编辑状态打开sql表 3.右键点击表最下面一行左侧的序号,选择粘贴(注意,excel的列一定要和sql表的列对应) 4.如果有自增,不要复制自增字段

如何将页面上的数据导入excel中

网上关于页面数据导入excel的文章很多,但是大部分都是关于 ActiveXObject 对象,可是ActiveXObject 对象是只支持IE的,可我连IE11也测试了,还是无法识别,又查到消息,好像该对象只支持IE7,IE8,所以果断放弃. 继续查找各大论坛,终于找到JsExcelXml的插件, <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></