Excel下载


  首先大数据量的下载,一般的Excel下载操作是不可能完成的,会导致内存溢出

  SXSSFWorkbook 是专门用于大数据了的导出  

  构造入参rowAccessWindowSize

  这个参数,会指定一个sheet可读取的row数目,超过该数目的row,会被写入到磁盘文件中,进而不能在通过getRow访问到,通过这种方式,内存使用空间就缩小很多了。 需要注意的是,如果该值指定为-1,说明不限制行数,所有记录都写入内存中;该值不能取0,因为这意味着任何新row都会写入磁盘,进而不能访问,但是新row还没来得及createCell

  setCompressTempFiles方法

  当写sheet的时候,临时文件可能远比结果文件要大,所以提供了压缩临时文件的接口,通过压缩,磁盘上的xml的临时文件将会被打包,进而降低磁盘占用空间。


先上代码再说

 /**
* Excel通用下载方法
* @param request
* @param response
* @param fileName
* 文件名
* @param titleNameList
* 标题头部
* @param cellNameList
* 行字段的name,主要用于map的get(),无则为null
* @param dataList
* 内容 支持类型 对象 map集合
*/
public static <E> void downLoad(HttpServletRequest request, HttpServletResponse response, String fileName,
List<String> titleNameList,List<String> cellNameList, List<E> dataList) {
OutputStream os = null;
try {
response.setContentType("application/force-download"); // 设置下载类型 response.setHeader("Content-Disposition", "attachment;filename=" + fileName); // 设置文件的名称
os = response.getOutputStream(); // 输出流
SXSSFWorkbook wb = new SXSSFWorkbook(1000);// 内存中保留 1000 条数据,以免内存溢出,其余写入 硬盘
// 获得该工作区的第一个sheet
Sheet sheet1 = wb.createSheet("sheet1");
String mapstring=null;
int excelRow = 0;
List<String> fieldNameList = new ArrayList<>();
// 标题行
Row titleRow = (Row) sheet1.createRow(excelRow++);
int titleSize = titleNameList.size();
for (int i = 0; i < titleSize; i++) {
Cell cell = titleRow.createCell(i);
cell.setCellValue(titleNameList.get(i));
}
int dataSize = dataList.size();
for (int i = 0; i < dataSize; i++) {
// 明细行
Row contentRow = (Row) sheet1.createRow(excelRow++);
Object object = dataList.get(i);
if (object instanceof Map) {
Map<String, Object> objectMap = (Map<String, Object>) object;
for (int j = 0; j < titleSize; j++) {
mapstring=objectMap.get(cellNameList.get(j))+"";
Cell cell = contentRow.createCell(j);
if (!"".equals(mapstring)&&mapstring!=null&&!"null".equals(mapstring)) {
cell.setCellValue(mapstring);
}else {
cell.setCellValue("");
}
}
} else { if (i == 0) {
if (cellNameList!=null&&cellNameList.size()>0) {
fieldNameList.addAll(cellNameList);
}else {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
fieldNameList.add(field.getName());
}
}
}
for (int j = 0; j < titleSize; j++) {
Cell cell = contentRow.createCell(j);
Field field = object.getClass().getDeclaredField(fieldNameList.get(j));
field.setAccessible(true);
Object fieldObj=field.get(object) ;
if (fieldObj != null&&!"null".equals(fieldObj)) {
cell.setCellValue(fieldObj.toString());
} else {
cell.setCellValue("");
} } }
}
wb.write(os);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
} // 关闭输出流
} }

读取大数据的Excel文件

直接上代码

public class SheetHandler extends DefaultHandler {
/**
* 单元格中的数据可能的数据类型
*/
enum CellDataType {
BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL
} /**
* 共享字符串表
*/
private SharedStringsTable sst; /**
* 上一次的索引值
*/
private String lastIndex; /**
* 文件的绝对路径
*/
private String filePath = ""; /**
* 工作表索引
*/
private int sheetIndex = 0; /**
* sheet名
*/
private String sheetName = ""; /**
* 总行数
*/
private int totalRows=0; /**
* 一行内cell集合
*/
private List<String> cellList = new ArrayList<String>(); /**
* 判断整行是否为空行的标记
*/
private boolean flag = false; /**
* 当前行
*/
private int curRow = 1; /**
* 当前列
*/
private int curCol = 0; /**
* T元素标识
*/
private boolean isTElement; /**
* 异常信息,如果为空则表示没有异常
*/
private String exceptionMessage; /**
* 单元格数据类型,默认为字符串类型
*/
private CellDataType nextDataType = CellDataType.SSTINDEX; private final DataFormatter formatter = new DataFormatter(); /**
* 单元格日期格式的索引
*/
private short formatIndex; /**
* 日期格式字符串
*/
private String formatString; //定义前一个元素和当前元素的位置,用来计算其中空的单元格数量,如A6和A8等
private String preRef = null, ref = null; //定义该文档一行最大的单元格数,用来补全一行最后可能缺失的单元格
private String maxRef = null; private int maxCol=0; private int nowcol;
/**
* 单元格
*/
private StylesTable stylesTable; /**
* 日期格式化 yyyy-MM-dd
*/
private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
/**
* 日期格式化
*/
private SimpleDateFormat sdf2=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /**
* 现在的时间
*/
private String dateTime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
/**
* 一个表格的所有数据
*/
private List<List<String>> sheetList=new ArrayList<>();
/**
* 操作人员
*/
private String userName; private static int startElements=0; private static int endElement=0;
/* public static void main(String[] args) {
SheetHandler sheetHandler=new SheetHandler();
File file=new File("C:\\Users\\Administrator\\Desktop\\jichu.xlsx"); try {
sheetHandler.process(new FileInputStream(file), "周光林");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
/**
* 遍历工作簿中所有的电子表格
* 并缓存在mySheetList中
*
* @param filename
* @throws Exception
*/
public List<List<String>> process(InputStream in,String userName) throws Exception {
this.userName=userName;
OPCPackage pkg = OPCPackage.open(in); XSSFReader xssfReader = new XSSFReader(pkg);
stylesTable = xssfReader.getStylesTable();
SharedStringsTable sst = xssfReader.getSharedStringsTable();
XMLReader parser = XMLReaderFactory.createXMLReader();
this.sst = sst;
parser.setContentHandler(this);
XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
while (sheets.hasNext()) { //遍历sheet
curRow = 1; //标记初始行为第一行
sheetIndex++;
InputStream sheet = sheets.next(); //sheets.next()和sheets.getSheetName()不能换位置,否则sheetName报错
sheetName = sheets.getSheetName();
// System.err.println(new BufferedReader(new InputStreamReader(sheet)).readLine());
InputSource sheetSource = new InputSource(sheet);
parser.parse(sheetSource); //解析excel的每条记录,在这个过程中startElement()、characters()、endElement()这三个函数会依次执行
sheet.close();
}
if (in!=null) {
in.close();
} return sheetList; //返回该excel文件的总行数,不包括首列和空行
} /**
* 第一个执行
*
* @param uri
* @param localName
* @param name
* @param attributes
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
//c => 单元格
if ("c".equals(name)) {
//当前单元格的位置
ref = attributes.getValue("r");
//设定单元格类型
this.setNextDataType(attributes);
}
//当元素为t时
if ("t".equals(name)) {
isTElement = true;
} else {
isTElement = false;
} //置空
lastIndex = "";
} /**
* 第二个执行
* 得到单元格对应的索引值或是内容值
* 如果单元格类型是字符串、INLINESTR、数字、日期,lastIndex则是索引值
* 如果单元格类型是布尔值、错误、公式,lastIndex则是内容值
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
lastIndex += new String(ch, start, length);
} /**
* 第三个执行
*
* @param uri
* @param localName
* @param name
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
//t元素也包含字符串
if (isTElement) {//这个程序没经过
//将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
String value = lastIndex.trim();
cellList.add(curCol, value);
curCol++;
isTElement = false;
//如果里面某个单元格含有值,则标识该行不为空行
if (value != null && !"".equals(value)) {
flag = true;
}
} else if ("v".equals(name)) { //v => 单元格的值,如果单元格是字符串,则v标签的值为该字符串在SST中的索引
String value = this.getDataValue(lastIndex.trim(), "");//根据索引值获取对应的单元格值
//补全单元格之间的空单元格
if (preRef!=null) {
if (!ref.equals(preRef)) {
int len = countNullCell(ref, preRef);
for (int i = 0; i < len; i++) { cellList.add(curCol, "");
curCol++;
}
}
}
preRef=ref; cellList.add(curCol, value);
curCol++;
//如果里面某个单元格含有值,则标识该行不为空行
if (value != null && !"".equals(value)) {
flag = true;
}
} else {
//如果标签名称为row,这说明已到行尾,调用optRows()方法
if ("row".equals(name)) {
//默认第一行为表头,以该行单元格数目为最大数目
if (curRow == 1) {
maxRef = ref;
maxCol=curCol;
}
//补全一行尾部可能缺失的单元格
if (maxRef != null) {
int len = countNullCell(maxRef, ref);
for (int i = 0; i <= len; i++) {
cellList.add(curCol, "");
curCol++;
}
}
if (flag&&curRow!=1){ //该行不为空行且该行不是第一行,则发送(第一行为列名,不需要)
nowcol=cellList.size();
if (cellList.size()<maxCol) {
for (int i = 0; i <maxCol-nowcol; i++) {
cellList.add("");
}
}
if (nowcol>maxCol) { for (int i = nowcol-1; i >maxCol-1; i--) {
cellList.remove(i);
}
}
cellList.add(userName);
cellList.add(dateTime); sheetList.add(new ArrayList<>(cellList));
totalRows++;
} cellList.clear();
curRow++;
curCol = 0;
preRef = null;
ref = null;
flag=false;
}
}
} /**
* 处理数据类型
*
* @param attributes
*/
public void setNextDataType(Attributes attributes) {
nextDataType = CellDataType.NUMBER; //cellType为空,则表示该单元格类型为数字
formatIndex = -1;
formatString = null;
String cellType = attributes.getValue("t"); //单元格类型
String cellStyleStr = attributes.getValue("s"); //
String columnData = attributes.getValue("r"); //获取单元格的位置,如A1,B1 if ("b".equals(cellType)) { //处理布尔值
nextDataType = CellDataType.BOOL;
} else if ("e".equals(cellType)) { //处理错误
nextDataType = CellDataType.ERROR;
} else if ("inlineStr".equals(cellType)) {
nextDataType = CellDataType.INLINESTR;
} else if ("s".equals(cellType)) { //处理字符串
nextDataType = CellDataType.SSTINDEX;
} else if ("str".equals(cellType)) {
nextDataType = CellDataType.FORMULA;
} if (cellStyleStr != null) { //处理日期
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
formatIndex = style.getDataFormat();
formatString = style.getDataFormatString(); if (formatString == null) {
nextDataType = CellDataType.NULL;
formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
}else if (formatString.contains("m/d/yy") || formatString.contains("yyyy/mm/dd")|| formatString.contains("yyyy/m/d")) {
nextDataType = CellDataType.DATE;
formatString = "yyyy-MM-dd";
}
}
} /**
* 对解析出来的数据进行类型处理
* @param value 单元格的值,
* value代表解析:BOOL的为0或1, ERROR的为内容值,FORMULA的为内容值,INLINESTR的为索引值需转换为内容值,
* SSTINDEX的为索引值需转换为内容值, NUMBER为内容值,DATE为内容值
* @param thisStr 一个空字符串
* @return
*/
@SuppressWarnings("deprecation")
public String getDataValue(String value, String thisStr) { switch (nextDataType) {
// 这几个的顺序不能随便交换,交换了很可能会导致数据错误
case BOOL: //布尔值
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR: //错误
thisStr = value.toString(); break;
case FORMULA: //公式
thisStr = '"' + value.toString() + '"'; break;
case INLINESTR:
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
thisStr = rtsi.toString();
rtsi = null;
break;
case SSTINDEX: //字符串
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
XSSFRichTextString rtss = new XSSFRichTextString(sst.getEntryAt(idx));//根据idx索引值获取内容值
thisStr = rtss.toString();
rtss = null;
} catch (NumberFormatException ex) {
thisStr = value.toString();
} break;
case NUMBER: //数字
if (formatString != null) {
thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString).trim();
} else {
thisStr = value;
} thisStr = thisStr.replace("_", "").trim();
break;
case DATE: //日期
try {
thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString);
}catch (Exception e) {
thisStr="0000-00-00";
} // 对日期字符串作特殊处理,去掉T
thisStr = thisStr.replace("T", " ");
break;
default:
if (Integer.parseInt(value)>20000) {
Date date = DateUtil.getJavaDate(Double.parseDouble(value));
thisStr =sdf.format(date);
}else {
thisStr="11111";
} break;
}
return thisStr;
} public int countNullCell(String ref, String preRef) {
//excel2007最大行数是1048576,最大列数是16384,最后一列列名是XFD
String xfd = ref.replaceAll("\\d+", "");
String xfd_1 = preRef.replaceAll("\\d+", ""); xfd = fillChar(xfd, 3, '@', true);
xfd_1 = fillChar(xfd_1, 3, '@', true); char[] letter = xfd.toCharArray();
char[] letter_1 = xfd_1.toCharArray();
int res = (letter[0] - letter_1[0]) * 26 * 26 + (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]);
return res - 1;
} public String fillChar(String str, int len, char let, boolean isPre) {
int len_1 = str.length();
if (len_1 < len) {
if (isPre) {
for (int i = 0; i < (len - len_1); i++) {
str = let + str;
}
} else {
for (int i = 0; i < (len - len_1); i++) {
str = str + let;
}
}
}
return str;
} /**
* @return the exceptionMessage
*/
public String getExceptionMessage() {
return exceptionMessage;
}
}
SheetHandler sheetHandler=new SheetHandler(); 

List<List<String>> lists=sheetHandler.process(in,userName);

Excel---导出与读取(大数据量)的更多相关文章

  1. [C#]_[使用微软OpenXmlSDK (OpenXmlReader)读取xlsx表格] 读取大数据量100万条数据Excel文件解决方案

      1.OpenXmlSDK是个很好的类库,可惜只能通过C#调用,C#的童鞋又福气了. 2.服务端程序由于没法安装office,所以这个对asp.net网站来说是最理想的库了.需要.net 4.0版本 ...

  2. C#读取大数据量Excel

    var worksheet = workbook.Worksheets["工作表1"]; var maxN = worksheet.Range["A1"].En ...

  3. java excel大数据量导入导出与优化

    package com.hundsun.ta.utils; import java.io.File; import java.io.FileOutputStream; import java.io.I ...

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

    1. Excel2003与Excel2007 两个版本的最大行数和列数不同,2003版最大行数是65536行,最大列数是256列,2007版及以后的版本最大行数是1048576行,最大列数是16384 ...

  5. poi 操作Excel 以及大数据量导出

    maven 依赖 (版本必须一致,否则使用SXSSFworkbook 时程序会报错) <dependency> <groupId>org.apache.poi</grou ...

  6. POI3.8解决导出大数据量excel文件时内存溢出的问题

    POI3.8的SXSSF包是XSSF的一个扩展版本,支持流处理,在生成大数据量的电子表格且堆空间有限时使用.SXSSF通过限制内存中可访问的记录行数来实现其低内存利用,当达到限定值时,新一行数据的加入 ...

  7. java 导出Excel 大数据量,自己经验总结!

    出处: http://lyjilu.iteye.com/ 分析导出实现代码,XLSX支持: /** * 生成<span style="white-space: normal; back ...

  8. NPOI大数据量多个sheet导出源码(原)

    代码如下: #region NPOI大数据量多个sheet导出 /// <summary> /// 大数据量多个sheet导出 /// </summary> /// <t ...

  9. [转]POI大数据量Excel解决方案

    全文转载自:jinshuaiwang的博客 目前处理Excel的开源javaAPI主要有两种,一是Jxl(Java Excel API),Jxl只支持Excel2003以下的版本.另外一种是Apach ...

随机推荐

  1. appium手机操作

    1.按键操作 pressKeyCode(key, metastate) key为按键事件,metastate为辅助功能键 举例: pressKeyCode(AndroidKeyCode.HOME)   ...

  2. 除了GPS外的4种获得用户地理位置数据的方法

    纯粹的GPS解决方案以及它所生成的经纬度标签是地理位置数据的公认标准.但是至少还有4种方法可以获得地理位置数据: 1.手机信号塔数据:当移动设备的GPS芯片不能接收到GPS信号时,移动设备就需要与它所 ...

  3. lxm --- ans lb config

    lxm --- ans lb config #ANS2.2 Build 160.006 # Last modified by `save config`, Fri Oct 12 17:15:42 20 ...

  4. 用Racket语言写了一个万花筒的程序

    用Racket语言写了一个万花筒的程序 来源:https://blog.csdn.net/chinazhangyong/article/details/79362394 https://github. ...

  5. xpose修改手机imei码,注入广告

      何为hook Hook英文翻译过来就是“钩子”的意思,那我们在什么时候使用这个“钩子”呢? 我们知道,在Android操作系统中系统维护着自己的一套事件分发机制.应用程序,包括应用触发事件和后台逻 ...

  6. hadoop(四)HDFS的核心设计

    一.hadoop心跳机制(heartbeat) 1. Hadoop 是 Master/Slave 结构, Master 中有 NameNode 和 ResourceManager, Slave 中有  ...

  7. 【贪心】【P5078】Tweetuzki 爱军训

    Description Tweetuzki 所在的班级有 \(n\) 名学生,座号从 \(1\) 到 \(n\).有一次,教官命令班上的 \(n\) 名学生按照座号顺序从左到右排成一排站好军姿,其中 ...

  8. Codeforces Round #209 (Div. 2)A贪心 B思路 C思路+快速幂

    A. Table time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...

  9. navicat for mysql 导出数据的坑

    navicat 选择转储结构和数据的时候,生成的 sql 文件会比较大,因为每一条数据都会生成一条 sql 语句,所以会导致 使用 source 还原的时候会很慢很慢很慢, 而使用 mysqldump ...

  10. openstack身份认证与API请求流程

    一.概况 1. 请求认证token时,需发送的认证信息包括: 2. 如果认证成功,会获得认证token 3. 在发送的API请求中将认证token填入X-Auth-Token字段.可以一直使用这个认证 ...