当记录数超出65536时,有两种方式处理:

一是调用WriteToDownLoad65536方法建立多个Excel。

二是调用WriteToDownLoad方法在同一个Excel中建多个Sheet。

若在同一Excel中建多个Sheet,若记录数达数十万,会导致字节流溢出的问题,解决办法是先获取MemoryStream,然后分块读取写入文件流。

需要注意的是在读取内存流的时候,一定要将内存流的位置设为0,因为在从HssfWorkBook中获取内存流时,位置已经置于最后了!若不重Position重新置为0则读取不到任何数据。

代码

using System;
using System.Collections.Generic;
using LuCeServiceWinForm.Common;
using NPOI.HSSF.UserModel;
using NPOI.HPSF;
using System.Web;
using System.IO;
using System.Data;
using NPOI.SS.UserModel;
using System.Reflection; namespace LuCeServiceWinForm.Helper
{
public class NPOIHelper
{
static HSSFWorkbook hssfworkbook; /// <summary>
/// 初始化
/// </summary>
static void InitializeWorkbook()
{
hssfworkbook = new HSSFWorkbook(); DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
dsi.Company = "";
hssfworkbook.DocumentSummaryInformation = dsi; SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
si.Subject = "";
hssfworkbook.SummaryInformation = si;
} /// <summary>
/// DataTable写入Excel
/// </summary>
/// <param name="FileName">要保存的文件名称 eg:test.xls</param>
/// <param name="SheetName">工作薄名称</param>
/// <param name="dt">要写入的DataTable </param>
public static void WriteToDownLoad(string FileName, string SheetName, DataTable dt)
{
string filename = FileName;
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", filename));
HttpContext.Current.Response.Clear(); //初始化Excel信息
InitializeWorkbook(); //填充数据
DTExcel(SheetName, dt, null); HttpContext.Current.Response.BinaryWrite(WriteToStream().GetBuffer());
HttpContext.Current.Response.End();
}
/// <summary>
/// 当大于65536条记录时,表格中建多个Sheet
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="FileName">要保存的文件名称 eg:test.xls</param>
/// <param name="SheetName">工作薄名称</param>
/// <param name="lst">要写入的List</param>
public static void WriteToDownLoad<T>(string FileName, string SheetName, List<T> lst, List<string> listTitle)
{
//初始化Excel信息
InitializeWorkbook();
//填充数据
//ListExcel<T>(SheetName, lst, listTitle);
//填充大于65536的数据
Fill65536(SheetName, lst, listTitle);
MemoryStream memoryStream = WriteToStream();
FileStream fstr = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.Write);
WriteMemoryStream(memoryStream, fstr);
}
public static void WriteToDownLoad<T>(string dir, string FileName, string SheetName, List<T> lst, List<string> listTitle)
{
try
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir); }
//初始化Excel信息
InitializeWorkbook(); //填充数据
ListExcel<T>(SheetName, lst, listTitle);
MemoryStream memoryStream = WriteToStream();
FileStream fstr = new FileStream(dir + "\\" + FileName + DateTime.Now.ToString("yyMMddHHmmss") + ".xls", FileMode.OpenOrCreate, FileAccess.Write);
WriteMemoryStream(memoryStream, fstr);
}
catch (Exception ex)
{
LogHelper.CreateLog(ex);
} }
/// <summary>
/// 将源内存流写入目标内存流
/// </summary>
/// <param name="memoryStream">源内存流</param>
/// <param name="fileStream">目标文件流</param>
private static void WriteMemoryStream(MemoryStream memoryStream, FileStream fileStream)
{
try
{
using (memoryStream)
{
using (fileStream)
{
//流的位置一定要归零,否则啥也读不到!
memoryStream.Position = ;
long len = memoryStream.Length;
byte[] buffer = new byte[ * ];//1MB=1024 * 1024
while (true)
{
int r = memoryStream.Read(buffer, , buffer.Length);
if (r <= )//表示读取到了文件的末尾
{
break;
}
else
{
fileStream.Write(buffer, , r);
double proc = (double)fileStream.Position / len;
LogHelper.WriteToLog("拷贝进度:" + proc * + "%");
} }
}
}
}
catch (Exception ex)
{
LogHelper.CreateLog(ex);
} }
/// <summary>
/// 从HssfWorkBook中获取内存流
/// </summary>
/// <returns></returns>
static MemoryStream WriteToStream()
{
MemoryStream file = new MemoryStream();
try
{
hssfworkbook.Write(file);
}
catch (Exception ex)
{
LogHelper.CreateLog(ex);
}
return file;
} #region 数据填充部分
/// <summary>
/// 将DataTable数据写入到Excel
/// </summary>
/// <param name="SheetName"></param>
/// <param name="dt"></param>
/// <param name="lstTitle"></param>
static void DTExcel(string SheetName, DataTable dt, List<string> lstTitle)
{
ISheet sheet1 = hssfworkbook.CreateSheet(SheetName);
int y = dt.Columns.Count;
int x = dt.Rows.Count; //给定的标题为空,赋值datatable默认的列名
if (lstTitle == null)
{
lstTitle = new List<string>();
for (int ycount = ; ycount < y; ycount++)
{
lstTitle.Add(dt.Columns[ycount].ColumnName);
}
} IRow hsTitleRow = sheet1.CreateRow();
//标题赋值
for (int yt = ; yt < lstTitle.Count; yt++)
{
hsTitleRow.CreateCell(yt).SetCellValue(lstTitle[yt]);
} //填充数据项
for (int xcount = ; xcount < x; xcount++)
{
IRow hsBodyRow = sheet1.CreateRow(xcount); for (int ycBody = ; ycBody < y; ycBody++)
{
hsBodyRow.CreateCell(ycBody).SetCellValue(dt.DefaultView[xcount - ][ycBody].ToString());
}
} } private static int index = ;
static void Fill65536<T>(string SheetName, List<T> lst, List<string> lstTitle)
{
++index;
if (lst.Count > )
{
ListExcel<T>(SheetName + index, lst.GetRange(, ), lstTitle);
lst.RemoveRange(, );
Fill65536(SheetName, lst, lstTitle);
}
else
{
ListExcel<T>(SheetName + index, lst, lstTitle);
index = ;
}
}
static void ListExcel<T>(string SheetName, List<T> lst, List<string> lstTitle)
{
ISheet sheet1 = hssfworkbook.CreateSheet(SheetName); T _t = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] propertys = _t.GetType().GetProperties(); //给定的标题为空,赋值T默认的列名
if (lstTitle == null)
{
lstTitle = new List<string>();
for (int ycount = ; ycount < propertys.Length; ycount++)
{
lstTitle.Add(((System.Reflection.MemberInfo)(propertys[ycount])).Name);//获取实体中列名称,去掉列类型
}
} IRow hsTitleRow = sheet1.CreateRow();
//标题赋值
for (int yt = ; yt < lstTitle.Count; yt++)
{
hsTitleRow.CreateCell(yt).SetCellValue(lstTitle[yt]);
} //填充数据项
for (int xcount = ; xcount <= lst.Count; xcount++)
{
IRow hsBodyRow = sheet1.CreateRow(xcount); for (int ycBody = ; ycBody < propertys.Length; ycBody++)
{
PropertyInfo pi = propertys[ycBody];
object obj = pi.GetValue(lst[xcount - ], null);
if (obj != null)
{
hsBodyRow.CreateCell(ycBody).SetCellValue(obj.ToString());
}
else
{
hsBodyRow.CreateCell(ycBody).SetCellValue("");
} }
} }
#endregion /// <summary>
/// 当大于65536条记录时,建多个Excel
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="folder"></param>
/// <param name="fileName"></param>
/// <param name="sheetName"></param>
/// <param name="list"></param>
/// <param name="listTitle"></param>
public static void WriteToDownLoad65536<T>(string folder, string fileName, string sheetName, List<T> list, List<string> listTitle)
{
if (list.Count > )
{
//填充
WriteToDownLoad<T>(folder, fileName, sheetName, list.GetRange(, ), listTitle);
list.RemoveRange(, );
//递归
WriteToDownLoad65536<T>(folder, fileName, sheetName, list, listTitle);
}
else
{
//填充
WriteToDownLoad<T>(folder, fileName, sheetName, list, listTitle);
}
} }
}

NPOIHelper

C#使用NPOI导出Excel的更多相关文章

  1. NPOI导出Excel (C#) 踩坑 之--The maximum column width for an individual cell is 255 charaters

    /******************************************************************* * 版权所有: * 类 名 称:ExcelHelper * 作 ...

  2. Asp.Net 使用Npoi导出Excel

    引言 使用Npoi导出Excel 服务器可以不装任何office组件,昨天在做一个导出时用到Npoi导出Excel,而且所导Excel也符合规范,打开时不会有任何文件损坏之类的提示.但是在做导入时还是 ...

  3. NPOI导出EXCEL 打印设置分页及打印标题

    在用NPOI导出EXCEL的时候设置分页,在网上有查到用sheet1.SetRowBreak(i)方法,但一直都没有起到作用.经过研究是要设置  sheet1.FitToPage = false; 而 ...

  4. .NET NPOI导出Excel详解

    NPOI,顾名思义,就是POI的.NET版本.那POI又是什么呢?POI是一套用Java写成的库,能够帮助开发者在没有安装微软Office的情况下读写Office的文件. 支持的文件格式包括xls, ...

  5. NPOI导出Excel(含有超过65335的处理情况)

    NPOI导出Excel的网上有很多,正好自己遇到就学习并总结了一下: 首先说明几点: 1.Excel2003及一下:后缀xls,单个sheet最大行数为65335 Excel2007 单个sheet ...

  6. [转]NPOI导出EXCEL 打印设置分页及打印标题

    本文转自:http://www.cnblogs.com/Gyoung/p/4483475.html 在用NPOI导出EXCEL的时候设置分页,在网上有查到用sheet1.SetRowBreak(i)方 ...

  7. 分享使用NPOI导出Excel树状结构的数据,如部门用户菜单权限

    大家都知道使用NPOI导出Excel格式数据 很简单,网上一搜,到处都有示例代码. 因为工作的关系,经常会有处理各种数据库数据的场景,其中处理Excel 数据导出,以备客户人员确认数据,场景很常见. ...

  8. 用NPOI导出Excel

    用NPOI导出Excel public void ProcessRequest(HttpContext context) { context.Response.ContentType = " ...

  9. NPOI导出Excel示例

    摘要:使用开源程序NPOI导出Excel示例.NPOI首页地址:http://npoi.codeplex.com/,NPOI示例博客:http://tonyqus.sinaapp.com/. 示例编写 ...

  10. NPOI导出excel(带图片)

    近期项目中用到Excel导出功能,之前都是用普通的office组件导出的方法,今天尝试用下NPOI,故作此文以备日后查阅. 1.NPOI官网http://npoi.codeplex.com/,下载最新 ...

随机推荐

  1. 修改Linux系统默认编辑器

    修改ubuntu的默认编辑器: echo export EDITOR=/usr/bin/vim >> ~/.bashrc 故障过程: 修改过程: 强制断开连接,重新连接,修改默认编辑器:e ...

  2. lamda表达式和stream

    stream主要用于处理数据,看一下jdk的文档,并且主要处理集合对象: int sum = widgets.stream() .filter(w -> w.getColor() == RED) ...

  3. git安装以及应用

    1.安装完成后,设置用户信息:$ git config --global user.name "wangfg"$ git config --global user.email &q ...

  4. react使用mobx

    mobx api 使用装饰器语法 mobx数据转化为js数据 安装 yarn add mobx mobx-react yarn add babel-preset-mobx --dev "pr ...

  5. JBPM工作流(七)——详解流程图

    概念: 流程图的组成: a. 活动 Activity / 节点 Node b. 流转 Transition / 连线(单向箭头) c. 事件 1.流转(Transition) a) 一般情况一个活动中 ...

  6. Kruskal和prime算法的类实现,图的遍历BFS算法。

    一.图的遍历 #include<iostream> #include<queue> #include<vector> using namespace std; in ...

  7. 16.1-uC/OS-III同步 (任务内建信号量)

    1.经常通过发送信号量实现同步.每个任务都有内建的信号量,通过任务内建的信号量不仅可以简化信号量通信的代码而且更加有效. 与任务内建的信号量相关的函数都是以 OSTaskSem???()为前缀的.相关 ...

  8. 海思编解码芯片添加64M nor flash

    uboot和内核都必须修改. struct spi_info hisfc350_spi_info_table[] : 在结构体里面添加自己的flash节点,我这里用的是MX66LS51235E { & ...

  9. 《Java程序设计》 第四周学习总结

    学号 20175313 <Java程序设计>第四周学习总结 教材学习内容总结 第五章主要内容 了解子类的继承性 子类和父类在同一包中的继承性(除private外其余都继承) 子类和父类不在 ...

  10. expdp 字符集从ZHS16GBK到AL32UTF8

    源oracle数据库是GBK字符集,目标库是UTF8字符集,现在需要将源库的一个表空间数据导入到目标库.我的解决方法有点繁琐,首先直接导出源库的表空间 expdp trmuser/trmpass sc ...