前言:公司让做一个导出数据到Excel的小工具,要求是用户前端输入sql语句,点击导出按钮之后,将数据导出到Excel,界面如图所示:文件下端显示导出的进度

遇到的问题:

1、使用NPOI进行Excel 的导出,使用XSSFWorkbook导出,这个类可以使每sheet条数超过十万条,使用HSSFWorkbook每个sheet只可以导出65535条数据。

2、导出数据时,创建新的线程进行导出,防止页面卡死不动。

3、在使用线程时,如果给线程方法传递参数,此示例中主要是通过

Thread t = new Thread(new ParameterizedThreadStart(T));
t.Start(filePath);

其中,T为线程方法;filePath为传递给T方法的参数。

T方法的声明:private void T(object o){}

由此可看出,T 的方法参数必须声明为object类型

4、在导出的过程中,如果一共有130万的数据,那么需要分n个Excel导出,一个Excel放130万的数据,并不是每台电脑都可以打开。

5、比如说一个Excel放30万数据,每次查询30万的数据,查询完之后,就生成一个Excel,然后再查询第二个30万,导出第二个Excel,读取完成一个,变量马上释放,防止内存溢出。

6、使用变量时,应及时释放,而且循环中最好不要声明变量,因为循环中声明变量的话,会导致不断的给变量分配内存,如果不及时释放的话,会导致内存溢出。

7、导出数据时,另起了一个线程(方法名称为T),这个线程不能直接获得页面上的控件,原因是页面上的控件和导数据的线程不是同一个,所以无法直接获取。可以通过线程SynchronizationContext实现:

SynchronizationContext m_SyncContext = null; //声明

public Form1()
{
InitializeComponent();
//获取UI线程同步上下文
m_SyncContext = SynchronizationContext.Current;
}

导出数据的线程方法T:

private void T(object o)

{

m_SyncContext.Post(SetTextSafePost, String.Format("{0:N0}", rate * 100) + "%");

}

其中,Post方法的第一个参数为声明的方法名,第二个参数为SetTextSafePost方法的参数

SetTextSafePost方法:

private void SetTextSafePost(object o)
{
label1.Text = "文件下载进度:" + o.ToString();
}

SetTextSafePost的方法的参数也是必须为Object类型

 7、在循环写入的Excel文档中时,将查询的结果集放大DataTable里不是一个好的解决方案,因为将所有的数据都放到DataTable里面是所有的数据都压到内存中,如果数据量过大的话,容易导致内存溢出。可以使用MySqlDataReader,while循环的过程中,将数据写入到Excel中。

代码示例:

using MySql.Data.MySqlClient;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms; namespace ExportDataBySQLToExcel
{
public partial class Form1 : Form
{
private string sql = "";
SynchronizationContext m_SyncContext = null;
public Form1()
{
InitializeComponent();
//获取UI线程同步上下文
m_SyncContext = SynchronizationContext.Current;
}
/// <summary>
/// 打开配置连接信息页面
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param> private void button2_Click(object sender, EventArgs e)
{
ConfigForm cf = new ConfigForm();
cf.ShowDialog(); }
/// <summary>
/// 导出按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param> private void button1_Click(object sender, EventArgs e)
{
sql = txtSql.Text;
if (sql == "")
{
MessageBox.Show("sql文本不允许为空,请确认");
return;
}
if (txtCount.Text == "")
{
MessageBox.Show("最大行数不允许为空,请确认");
return;
}
if (txtSize.Text == "")
{
MessageBox.Show("总条数不能为空");
}
SaveFileDialog sfd = new SaveFileDialog();
//sfd.Filter = "Excel文件(*.xls)|*.xls|Excel文件(*.xlsx)|*.xlsx";
sfd.Filter = "Excel文件(*.xlsx)|*.xlsx"; if (sfd.ShowDialog() == DialogResult.OK)
{
button1.Enabled = false;
button2.Enabled = false;
label1.Text = "文件下载中...";
string filePath = sfd.FileName;
Thread t = new Thread(new ParameterizedThreadStart(T));
t.Start(filePath);
} }
/// <summary>
/// 线程方法
/// </summary>
private void T(object o)
{
string fileName;
string[] fileNames = o.ToString().Split('.');
XSSFWorkbook workbook = null;
try
{
//创建表
ISheet sheet = null;
ICellStyle cellStyle = null;
NPOI.SS.UserModel.IFont cellfont = null; //获得DataTable
MySqlHelper.connectionStringManager = PubClass.getConnString();
IRow headerRow = null;
ICell cell = null;
int count = int.Parse(txtCount.Text); //一个Excel的总条数 int rowIndex = ; //行标
int maxRowNum = ;
int minRowNum = ;
string mysql = "";
//string countsql = string.Format("SET @rows=0; SELECT ROWNUM FROM ({0}) AS A ORDER BY ROWNUM DESC LIMIT 1", sql, minRowNum, maxRowNum);
//DataTable dt = MySqlHelper.GetDataTable(null, CommandType.Text, countsql);
if (txtSize.Text!="")
{
int size = int.Parse(txtSize.Text); // 1130389;
//size = int.Parse(dt.Rows[0]["ROWNUM"].ToString());
int index = size / count + (size % count > ? : );
for (int i = ; i < index; i++)
{
m_SyncContext.Post(SetTextSafePost, string.Format("第{0}个Excel数据正在读取数据,请稍后.....", i + ));
//创建工作薄
workbook = new XSSFWorkbook();
sheet = workbook.CreateSheet("Sheet1");
#region 样式
ICellStyle HeadercellStyle = workbook.CreateCellStyle();
HeadercellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
HeadercellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
HeadercellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
HeadercellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
HeadercellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
//字体
NPOI.SS.UserModel.IFont headerfont = workbook.CreateFont();
headerfont.Boldweight = (short)FontBoldWeight.Bold;
HeadercellStyle.SetFont(headerfont); cellStyle = workbook.CreateCellStyle();
//为避免日期格式被Excel自动替换,所以设定 format 为 『@』 表示一率当成text來看
cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("@");
cellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
cellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
cellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; cellfont = workbook.CreateFont();
cellfont.Boldweight = (short)FontBoldWeight.Normal;
cellStyle.SetFont(cellfont); #endregion rowIndex = ;
minRowNum = i * count;
maxRowNum = (i + ) * count;
mysql = string.Format("SET @rows=0; SELECT * FROM ({0}) AS A WHERE A.ROWNUM>{1} AND a.ROWNUM<={2}", sql, minRowNum, maxRowNum);
using (MySqlDataReader reader = MySqlHelper.ExecuteReader(MySqlHelper.connectionStringManager, CommandType.Text, mysql, null))
{
int columns = reader.FieldCount; //获得总列数
while (reader.Read())
{
if (rowIndex == )
{
headerRow = sheet.CreateRow();
for (int colIndex = ; colIndex < columns; colIndex++)
{
cell = headerRow.CreateCell(colIndex);
cell.SetCellValue(reader.GetName(colIndex).Trim());
cell.CellStyle = HeadercellStyle;
}
}
headerRow = sheet.CreateRow(rowIndex + );
for (int colIndex = ; colIndex < columns; colIndex++)
{
cell = headerRow.CreateCell(colIndex);
cell.SetCellValue(reader[reader.GetName(colIndex)].ToString());
cell.CellStyle = cellStyle;
}
rowIndex++;
} }
if (workbook.GetSheet("Sheet1").GetRow() != null)
{
m_SyncContext.Post(SetTextSafePost, String.Format("第{0}个Excel读取数据完毕,正在写入Excel文件中,请稍后.....", i + ));
fileName = fileNames[] + (i + ).ToString() + "." + fileNames[];
SaveExcel(fileName, workbook);
}
else
{
break;
} workbook = null;
}
m_SyncContext.Post(SetTextSafePost, String.Format("导出成功"));
m_SyncContext.Post(setButtonEnable, true);
MessageBox.Show("导出成功", "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);
} }
catch (Exception ex)
{
m_SyncContext.Post(SetTextSafePost, String.Format("导出失败"));
m_SyncContext.Post(setButtonEnable, true);
MessageBox.Show("导出失败,提示信息为:" + ex.Message, "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
finally
{
workbook = null;
//将WorkBook写入到File中
//for (int i = 0; i < lstWorkBook.Count; i++)
//{
// fileName = fileNames[0] + i.ToString() + "." + fileNames[1];
// SaveExcel(fileName, lstWorkBook[i]);
//}
}
}
private void SaveExcel(string fileName, XSSFWorkbook workbook)
{
if (workbook != null)
{
//转为字节数组
MemoryStream stream = new MemoryStream();
workbook.Write(stream);
var buf = stream.ToArray();
//保存为Excel文件
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
fs.Write(buf, , buf.Length);
fs.Flush();
}
}
}
private void SetTextSafePost(object o)
{
label1.Text = o.ToString();
}
private void setButtonEnable(object o)
{
button1.Enabled = (bool)o;
button2.Enabled = (bool)o;
label1.Text = "文件下载完成";
} /// <summary>
/// 没用的代码
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
sql = txtSql.Text;
txtCount.Text = "";
txtSize.Text = "";
}
}
}

Winform .NET 利用NPOI导出大数据量的Excel的更多相关文章

  1. Struts2 利用AJAX 导出大数据设置遮罩层

    Struts2 利用AJAX 导出大数据设置遮罩层 需求背景: 每次我们导出excel的时候 ,如果数据量很大,导出花费的时间会很长,页面却有没人任何反应,这个时候用户会认为系统有问题,要么关了页面, ...

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

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

  3. 有效提升大数据量写入excel的效率

    在开发过程中经常会有需要将数据导出到 excel 的需求,当数据量很大,达到几万甚至几十万.几百万级别的时候,如何加快生成 excel 的速度呢?首先普及一下知识背景:Excel2003 及以下版本一 ...

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

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

  5. SQL Server 使用bcp进行大数据量导出导入

    转载:http://www.cnblogs.com/gaizai/archive/2010/04/17/1714389.html SQL Server的导出导入方式有: 在SQL Server中提供了 ...

  6. MySQL数据库如何解决大数据量存储问题

    利用MySQL数据库如何解决大数据量存储问题? 各位高手您们好,我最近接手公司里一个比较棘手的问题,关于如何利用MySQL存储大数据量的问题,主要是数据库中的两张历史数据表,一张模拟量历史数据和一张开 ...

  7. POI读写大数据量EXCEL

    另一篇文章http://www.cnblogs.com/tootwo2/p/8120053.html里面有xml的一些解释. 大数据量的excel一般都是.xlsx格式的,网上使用POI读写的例子比较 ...

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

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

  9. (转)利用WPF的ListView进行大数据量异步加载

    原文:http://www.cnblogs.com/scy251147/archive/2012/01/08/2305319.html 由于之前利用Winform的ListView进行大数据量加载的时 ...

随机推荐

  1. python ----django---打包重用

    https://www.cnblogs.com/wcwnina/p/9122469.html https://blog.csdn.net/qq_30501975/article/details/804 ...

  2. centos7,zabbix3.2通过zabbix_java_gateway监控jmx[java/tomcat]

    网络上很多教程也比较多和全了,但是自己做时候多多少少的坑备注下吧. 1,监控原理简单说一下,就是zabbix_server通过代理(zabbix_java_gateway)来获取agent端(tomc ...

  3. linux7 安装 zlib依赖库 与安装python 3.6

    Linux 安装zlib依赖库 进入src: cd /usr/local/src 下载zlib库: wget http://www.zlib.net/zlib-1.2.11.tar.gz 解压下载的t ...

  4. python安装与pip操作

    python安装 1, 下载并解压Python-3.6.2.tar.xz 2,tar xvJf Python-3.6.2.tar.xz 2./configure --prefix=/usr/local ...

  5. 解决IIS配置问题

    解决网站运行一段时间会变慢的问题 http://blog.csdn.net/rryqsh/article/details/8156558 1. IIS 7 应用程序池自动回收关闭的解决方案 如果你正在 ...

  6. kvm动态添加硬盘

    1.创建硬盘. qemu-img create -f qcow2 /data/data_root/vm-images/xxxx.qcow2 20G 2.添加硬盘 方式1.动态添加: virsh att ...

  7. 循环输入到列表的基础方法 -----python-----

    print('向列表中添加元素(输入“#”结束)\n并查看添加完的列表') list1=[] while 1: username=input('>>>') if (username. ...

  8. SpringCloud-day07-Feign

    7.Feign 7.1.Feign简介 声明式服务调用Feign简单介绍下: Feign是一个声明式的Web Service客户端,它使得编写Web Serivce客户端变得更加简单.我们只需要使用F ...

  9. LocalDate的使用

    LocalDate的一些使用方法 今天半天的时间都用在了LocalDate上,然后呢,也是自己的第一次写博客. 首先来看看会用上的方法吧. 两个构造器,用的是静态工厂方法 static   Local ...

  10. java、asp.net 通用分页码函数

    <script type="text/javascript"> $(document).ready(function(){ ajaxGetPaging(1); }); ...