Java 利用POI对象 SXSSFWorkbook 导出Excel_sxssfwworkbook下载excel示例-程序员宅基地

技术标签: Java  POI  SXSSF  Excel 导出  


利用 SXSSFWorkbook 生成导出.xlsx文件

一、基础介绍请戳:CSV与Excel的对比,POI导出Excel的数据量限制,HSSF、XSSF、SXSSF的区别


二、SXSSFWorkbook:低内存占用的工作簿

引用官方的介绍,简单概括就是:
SXSSF是对XSSF的一种流式扩展,特点和原理是采用了滑动窗口的机制,低内存占用,主要用于数据量非常大的电子表格而虚拟机堆有限的情况。

SXSSFWorkbook.DEFAULT_WINDOW_SIZE默认值是100,表示在内存中最多存在100个Row对象,当写第101个Row对象的时候就会把第1个Row对象以XML格式写入C:\Users\wange\AppData\Local\Temp路径下的临时文件中,后面的以此类推,始终保持内存中最多存在100个Row对象。

SXSSFWorkbook默认使用内联字符串而不是共享字符串表(SharedStringsTable)。启用共享字符串时,文档中的所有唯一字符串都必须保存在内存中,因此XSSF会占用更多的内存。

与XSSF的对比,在一个时间点上,只可以访问一定数量的Row;不再支持Sheet.clone();不再支持公式的求值。但是除了滑动窗口,其余的EXCLE操作仍然使用的是XSSF的API。

官方提示导出EXCEL后应该调用wb.dispose()来删除之前保存的临时文件。

三、SXSSFWorkbook导出Excel示例

通过poi导出excel的过程大致是这样的:

  • 导入POI的jar包,使用对应的POI对象(本篇选择SXSSFWorkbook)
  • 创建 sheet 表
  • 创建 row 行
  • 创建 cell 每行的单元格(可设置数据的格式,和单元格的格式)
  • 也可在所有数据写好之后,整体对某列某行来设置格式
  • 通过IO流输出

SXSSFWorkbook的使用,与HSSFWorkbook基本一致,只需要换掉对应的Sheet、Row、Cell等类就可以了;

sheet,row,cell在建立的时候Index都是从0开始的;

/**
 * 生成导出.xls文件,使用SXSSFWorkbook
 */
public static File createExcelFile(List<Map<String, String>> exportData,
            Map<String, String> rowMapper, String outPutPath,
            String excelFileName) {
    
    File excelFile = null;
    FileOutputStream fOut = null;
    SXSSFWorkbook wb = null;
    try {
    
        excelFile = File.createTempFile(excelFileName, ".xls", new File(outPutPath));
        //wb对象
        wb = new SXSSFWorkbook();
        //创建sheet对象
        Sheet sheet = wb.createSheet();
        //设置列默认的宽度
        sheet.setDefaultColumnWidth(15);
        //创建表头行
        Row rowHead = sheet.createRow(0);
        //设置表头行内容,可以在这里对表头设置一些样式,标红呀,加粗之类的
        //样式代码在下面有示范
        int i = 0;
        for (String str : rowMapper.values()) {
    
            Cell cellHead = rowHead.createCell(i);
            cellHead.setCellValue(str);
            i++;
        }

单元格格式的创建需在循环体外,不然数据量过大时会报错:“The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook”

	    //设置表格主内容
	    //单元格格式的创建需在循环体外,不然数据量过大时会报错
	    CellStyle textStyle = wb.createCellStyle();
	    //用于格式化单元格的数据
	    DataFormat format = wb.createDataFormat();
	    //设置为单元格文本格式
	    textStyle.setDataFormat(format.getFormat("@"));
	    //不换行
		textStyle.setWrapText(false);
		int j = 0;
		for (Map<String, String> datamap : exportData) {
    
		    Row row = sheet.createRow(j + 1);
		    int k = 0;
		    for (String str : datamap.keySet()) {
    
		        Cell cell = row.createCell(k);
	  	      //判断针对单号数据,需要设置单元格格式为文本格式,避免科学计数法
	   	        if (("身份证号").equals(rowMapper.get(str))) {
    
	            	cell.setCellStyle(textStyle);
	            	cell.setCellValue(datamap.get(str));
	            	cell.setCellType(Cell.CELL_TYPE_STRING);
	        	} else {
    
	            	cell.setCellValue(datamap.get(str));
	        	}
	        	k++;
	 		}
	 		j++;
		}  
	    fOut = new FileOutputStream(excelFile);
	    //写内容,xls文件已经可以打开
	    wb.write(fOut);
	    //刷新缓冲区
	    fOut.flush();
    } catch (IOException e) {
    
        logger.error("export IOException");
    } finally {
    
        try{
    
           fOut.close();
           //删除之前保存的临时文件
           wb.dispose();
        }catch (Exception ex){
    
           logger.error("export io exception");
        }
    }
    return excelFile;
}

四、SXSSF单元的样式设置,标红加粗之类

// 设置单元格各种样式
// 设置字体
Font font = wb.createFont();
//字体高度
font.setFontHeightInPoints((short) 11); 
//字体颜色
font.setColor(Font.COLOR_NORMAL); 
//字体
font.setFontName("宋体"); 

//设置单元格里的字体样式,使用上面设置对字体样式,以及设置单元格的格式
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setFont(font);
//水平布局:居中
cellStyle.setAlignment(CellStyle.ALIGN_CENTER); 
//单元格垂直居中
cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
//换行
cellStyle.setWrapText(true);

五、对于身份证等长数字数据,设置CELL单元格为文本格式

/**
*设置CELL格式为文本格式  
*/
CellStyle cellStyle = wb.createCellStyle();  
DataFormat format = wb.createDataFormat();  

//"@"是指文本的数据格式,主要是这段代码
cellStyle.setDataFormat(format.getFormat("@"));  
cell.setCellStyle(cellStyle);  
cell.setCellValue(你的值);
  
//CELL_TYPE_STRING是单元格格式,这里写不写没区别…… 原因如下解释
cell.setCellType(Cell.CELL_TYPE_STRING);
踩坑点:
  • 通常大家都是想到既然是设置CELL格式肯定是通过cell.setCellType(HSSFCell.CELL_TYPE_STRING)然后插入数据再导出,诚然这种想法是对的,实际上不能起到任何作用,因为这个方法就是EXCEL默认的格式,写不写都一样;
  • 如果数据量大的话,系统可能会报错“The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook”,原因是cellStyle创建的次数太多了,解决这个问题的方法很简单,在循环体外面创建单元格格式(即把它当成一个“全局”变量),不要在循环内部创建;
  • 自调节单元格尺寸方法 autoSizeColumn(), api描述说数据较大时耗时非常大, 建议在结果的时候调用一次。(ps:autoSizeColumn会遍历每一列的每一行数据获取最大长度)

六、自定义写临时文件规则:SXSSFWorkbook wb = new SXSSFWorkbook(-1)

初始化设置为-1的时候我们可以自己定义写临时文件规则,比如每读1000行记录flush到临时一次,可以大大减少磁盘IO次数。

七、拼好Excel之后,文件下载方法:

方法1:
//创建xls文件,无内容 0字节
FileOutputStream fOut = new FileOutputStream(xlsFile);        
//写内容,xls文件已经可以打开
wb.write(fOut);                            
//刷新缓冲区
fOut.flush();
//关闭                            
fOut.close();                            
方法2:
 //生成流对象
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();    
//将excel写入流        
wb.write(byteArrayOutputStream);                                
//工具类,封装弹出下载框:        
String outFile = "excelFile.xls";
DownloadBaseAction down = new DownloadBaseAction();
down.download(byteArrayOutputStream, response, outFile);
方法3:(适用于struts2)
ServletActionContext.getResponse().setContentType("application/octet-stream");
String returnName = ServletActionContext.getResponse().encodeURL( new String("excelFile.xls".getBytes(), "ISO-8859-1"));
ServletActionContext.getResponse().addHeader("Content-Disposition", "attachment;filename=" + returnName);
wb.write(ServletActionContext.getResponse().getOutputStream());

八、SXSSFWorkbook 没有提供读取文件流的方法。因此读入大数据量的时候还是只能使用XSSFWorkbook来读取

OPCPackage pkg = OPCPackage.open(filename);
XSSFReader xssfReader = new XSSFReader(pkg);

使用SAX模型来解析EXCEL不像DOM模型一下把所有文件内容加载进内存,它逐行扫描文档,一边扫描,一边解析。所以那些只需要单遍读取内容的应用程序就可以从SAX解析中受益,这对大型文档的解析是个巨大优势。


参考链接

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43525116/article/details/88063722

智能推荐

Java 1.8(圆的面积和周长)编写程序,使用以下公式计算并显示半径为5.5的圆的面积和周长。_java程序 已知圆的半径是5.6-程序员宅基地

文章浏览阅读2.1k次,点赞6次,收藏7次。package Try;import java.util.Scanner;//在java.util中导入Scanner包public class Circle { public static void main(String[] args) { System.out.println("请输入圆的半径");//友情提示 Scanner input = new Scanner(System.in);//创建一个名为input的输入环境 ._java程序 已知圆的半径是5.6

华为鸿蒙开发者大会什么时候召开,鸿蒙2.0来了!华为正式公布开发者大会时间:9月10日...-程序员宅基地

文章浏览阅读416次。原标题:鸿蒙2.0来了!华为正式公布开发者大会时间:9月10日8月2日晚上8点,华为通过官方微博正式对外宣布了华为开发者大会HDC2020的召开时间为9月10日至12日。这一消息与此前爆料的华为将于9月11日召开开发者大会的消息基本吻合。 不出意外的话,这场开发者大会的重头戏,将会是备受期待的鸿蒙2.0操作系统。因为按照去年华为开发者大会公布的鸿蒙系统应用时间表,今年华为将会上马鸿蒙2.0操作系统..._7月8鸿蒙鲲鹏大会什么时候召开

批量栅格投影(arcpy)_arcpy 摨西蓮銝箇掖-程序员宅基地

文章浏览阅读3.2k次,点赞3次,收藏20次。栅格投影的意义:将分辨率单位为度的变为米定义投影的意义:将某个栅格的坐标系变为想要的坐标系批量栅格投影的代码如下:# -*- coding: UTF-8 -*-#需要自行更改的如下:#inws:输入路径#outws:输出路径#Coordinate_System:目标投影坐标系import globimport osimport arcpy# 输入路径 应该注意,中文路径,会导致读不出文件inws = r"------"# 参考文件路径 使用栅格数据集(从其导入方形像元大_arcpy 摨西蓮銝箇掖

《Malware Analysis and Detection Engineering》第一章:恶意软件趋势与反病毒人员架构-程序员宅基地

文章浏览阅读279次。malspam 垃圾邮件_malware analysis and detection engineering

JavaEE--spring(4)_javaee配置异常通知-程序员宅基地

文章浏览阅读111次。AOPAOP:全称是 Aspect Oriented Programming 即:面向切面编程。简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。AOP的作用及优势:作用: 在程序运行期间,不修改源码对已有方法进行增强。优势: 减少重复代码 提高开发效AOP的实现方式:使用动态代理技术AOP 相关术语Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的_javaee配置异常通知

ValueError: not enough values to unpack (expected 3, got 2)-程序员宅基地

文章浏览阅读1.1w次,点赞4次,收藏4次。python报错:ValueError: not enough values to unpack (expected 3, got 2)分析:这个错误的信息是,期望有三个返回值,但其实函数只有两个返回值解决方法,检查函数和接收函数返回值的参数个数是否一致,改成一致即可..._valueerror: not enough values to unpack (expected 3, got 2)

随便推点

[kuangbin带你飞]专题一 简单搜索 K - 迷宫问题-程序员宅基地

文章浏览阅读87次。K - 迷宫问题定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0,};它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。Input一个5 × 5...

解决SQL Server 2014 Management Studio无法将excel数据导入数据库_标题: sql server 导入和导出向导 ----------------------------程序员宅基地

文章浏览阅读1.2k次。标题: SQL Server 导入和导出向导------------------------------操作无法完成。------------------------------其他信息:未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。 (System.Data)针对上面这个问题,可以尝试下载安装AccessDatabaseEngine.e..._标题: sql server 导入和导出向导 ------------------------------ 操作无法完成

无法获得 VMCI 驱动程序的版本: 句柄无效_visual machine communication interface(vmci)驱动程序-程序员宅基地

文章浏览阅读1.6k次。今天打开虚拟机遇到了一些问题,一直在网上查也没用,最后十分粗暴的重装了一遍。安装后打开的时候遇到了这个问题,查了一下解决了。在此记录一下。首先看一下VMCI。虚拟机交流接口VMCI(The Virtual Machine Communication Interface)是一个在一个或多个虚拟机与宿主机之间提供高速高效交流的基本组件(infrastructure)启用一个虚拟机的VMCI..._visual machine communication interface(vmci)驱动程序

(Python实用)用Python做的交互式动态大图_python pyecharts 动态放大-程序员宅基地

文章浏览阅读1.4k次。今天给大家分享1个pyecharts交互式动态可视化案例,通过先拆分、后组合的方式,一步步教你如何实现,具体成果如下。本次案例数据来源于国家统计局,通过爬虫获取,这里已给大家备好,请在文末获取一、绘制基本图形用pandas读取数据,通过整合数据格式,分别用pyecharts绘制地图、柱状图、饼图,具体内容如下:1.绘制地图importpyecharts.optionsasoptsfrompyecharts.globalsimportThemeTypefrompye..._python pyecharts 动态放大

LayUI upload上传组件上传文件的两种方式(手动上传、自动上传)_layui upload auto-程序员宅基地

文章浏览阅读8.3k次,点赞7次,收藏8次。1 手动上传上传文件分为两步,第一步选择文件,第二步上传文件。HTML代码:<input type='button' id='selectFile' value='选择文件'><div id='fileDiv'></div><input type='button' id='uploadFile' value='上传文件'>JS代码:$(function(){ initUpload();});//初始化上传组件funct_layui upload auto

CPU与外设之间的数据传送方式_cpu与外设采用无条件传送方式时,为保证传送数据的有效性,对外设有什么要求-程序员宅基地

文章浏览阅读2w次,点赞18次,收藏57次。在微型计算机系统中,CPU与外设之间的数据传送方式主要有程序传送方式、中断传送方式和直接存储器存取(DMA)传送方式,分别介绍如下。 7.2.1 程序传送方式 程序传送方式是指直接在程序控制下进行数据的输入/输出操作。程序查询方式分为无条件传送方式和查询方式(条件传送方式)两种。 一. 无条件传送方式 微机系统中的一些简单的外设,如开关、继电器、数码管、发光二极管等_cpu与外设采用无条件传送方式时,为保证传送数据的有效性,对外设有什么要求

推荐文章

热门文章

相关标签