在做winform窗体编程的时候,很多时候都需要把datatable中的数据或者datagridview中的数据导出到excel中,供用户查看。而且在导出时又分为单文件单表格和单文件多表格导出。
单文件单表格:一个excel文件,里面只有一个sheet
单文件多表格:一个excel文件,里面有多个sheet
话不多说,直接上代码:
导出辅助类:
using NPOI.HSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class ExcelHelp
{
[DllImport("kernel32.dll")]
public static extern IntPtr _lopen(string lpPathName, int iReadWrite);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hObject);
public const int OF_READWRITE = 2;
public const int OF_SHARE_DENY_NONE = 0x40;
public readonly IntPtr HFILE_ERROR = new IntPtr(-1);
/// <summary>
/// NPOI DataGridView 导出 EXCEL
/// </summary>
/// <param name="fileName"> 默认保存文件名</param>
/// <param name="dgv">DataGridView</param>
/// <param name="fontname">字体名称</param>
/// <param name="fontsize">字体大小</param>
public void ExportExcel(string fileName, DataGridView dgv, string fontname, short fontsize)
{
//检测是否有数据
//定义表格内数据的行数和列数
int rowscount = dgv.Rows.Count;
int colscount = dgv.Columns.Count;
//行数必须大于0
if (rowscount <= 0)
{
MessageBox.Show("没有数据可供保存 ", "提示 ", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
//列数必须大于0
if (colscount <= 0)
{
MessageBox.Show("没有数据可供保存 ", "提示 ", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
//if (dgv.SelectedRows.Count == 0) return;
//创建主要对象
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = (HSSFSheet)workbook.CreateSheet("Weight");
//设置字体,大小,对齐方式
HSSFCellStyle style = (HSSFCellStyle)workbook.CreateCellStyle();
HSSFFont font = (HSSFFont)workbook.CreateFont();
font.FontName = fontname;
font.FontHeightInPoints = fontsize;
style.SetFont(font);
style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER; //居中对齐
//添加表头
HSSFRow dataRow = (HSSFRow)sheet.CreateRow(0);
for (int i = 0; i < dgv.Columns.Count; i++)
{
dataRow.CreateCell(i).SetCellValue(dgv.Columns[i].HeaderText);
dataRow.GetCell(i).CellStyle = style;
}
//注释的这行是设置筛选的
//sheet.SetAutoFilter(new CellRangeAddress(0, dgv.Columns.Count, 0, dgv.Columns.Count));
//添加列及内容
for (int i = 0; i < dgv.Rows.Count ; i++)
{
dataRow = (HSSFRow)sheet.CreateRow(i + 1);
for (int j = 0; j < dgv.Columns.Count; j++)
{
string ValueType = dgv.Rows[i].Cells[j].Value.GetType().ToString();
string Value = dgv.Rows[i].Cells[j].Value.ToString().Trim();
switch (ValueType)
{
case "System.String"://字符串类型
dataRow.CreateCell(j).SetCellValue(Value);
break;
case "System.DateTime"://日期类型
System.DateTime dateV;
System.DateTime.TryParse(Value, out dateV);
dataRow.CreateCell(j).SetCellValue(dateV);
break;
case "System.Boolean"://布尔型
bool boolV = false;
bool.TryParse(Value, out boolV);
dataRow.CreateCell(j).SetCellValue(boolV);
break;
case "System.Int16"://整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
int intV = 0;
int.TryParse(Value, out intV);
dataRow.CreateCell(j).SetCellValue(intV);
break;
case "System.Decimal"://浮点型
case "System.Double":
double doubV = 0;
double.TryParse(Value, out doubV);
dataRow.CreateCell(j).SetCellValue(doubV);
break;
case "System.DBNull"://空值处理
dataRow.CreateCell(j).SetCellValue("");
break;
case "System.Byte[]"://二进制文件
string str = System.Text.Encoding.GetEncoding("iso-8859-1").GetString((byte[])dgv.Rows[i].Cells[j].Value);
// byte[] data = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(str);
if (str.Length < 31000)
{
dataRow.CreateCell(j).SetCellValue(str);
}
else
{
string strSub = "";
for (int n = 0; n <= str.Length / 30000; n++)
{
if (str.Length - n * 30000 - 1 >= 30000)
strSub = str.Substring(n * 30000, 30000);
if (str.Length - n * 30000 - 1 < 30000)
strSub = str.Substring(n * 30000, str.Length - n * 30000);
dataRow.CreateCell(j + n).SetCellValue(strSub);
}
}
break;
default:
dataRow.CreateCell(j).SetCellValue("");
break;
}
dataRow.GetCell(j).CellStyle = style;
// 设置宽度
sheet.SetColumnWidth(j, (Value.Length + 10) * 256);
}
}
//保存文件
string saveFileName = "";
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.DefaultExt = "xls";
saveDialog.Filter = "Excel文件|*.xls";
saveDialog.FileName = fileName;
MemoryStream ms = new MemoryStream();
if (saveDialog.ShowDialog() == DialogResult.OK)
{
saveFileName = saveDialog.FileName;
if (!CheckFiles(saveFileName))
{
MessageBox.Show("文件被占用,请关闭文件 " + saveFileName);
workbook = null;
ms.Close();
ms.Dispose();
return;
}
workbook.Write(ms);
FileStream file = new FileStream(saveFileName, FileMode.Create);
workbook.Write(file);
file.Close();
workbook = null;
ms.Close();
ms.Dispose();
MessageBox.Show("文件保存成功", "提示", MessageBoxButtons.OK);
}
else
{
workbook = null;
ms.Close();
ms.Dispose();
}
}
/// <summary>
/// 检测文件被占用
/// </summary>
/// <param name="FileNames">要检测的文件路径</param>
/// <returns></returns>
public bool CheckFiles(string FileNames)
{
IntPtr vHandle = _lopen(FileNames, OF_READWRITE | OF_SHARE_DENY_NONE);
if (vHandle == HFILE_ERROR)
{
//文件被占用
return false;
}
//文件没被占用
CloseHandle(vHandle);
return true;
}
public void ExportExcel2( MemoryStream ms ,Dictionary<string,DataTable> dic, string fontname, short fontsize,string saveFileName)
{
//if (dt.SelectedRows.Count == 0) return;
//创建主要对象
HSSFWorkbook workbook = new HSSFWorkbook();
DataTable dt;
foreach (string item in dic.Keys)
{
string sf = item.Trim();
dic.TryGetValue(sf,out dt);
HSSFSheet sheet = (HSSFSheet)workbook.CreateSheet(sf);
//设置字体,大小,对齐方式
HSSFCellStyle style = (HSSFCellStyle)workbook.CreateCellStyle();
HSSFFont font = (HSSFFont)workbook.CreateFont();
font.FontName = fontname;
font.FontHeightInPoints = fontsize;
style.SetFont(font);
style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER; //居中对齐
//添加表头
HSSFRow dataRow = (HSSFRow)sheet.CreateRow(0);
for (int i = 0; i < dt.Columns.Count; i++)
{
dataRow.CreateCell(i).SetCellValue(dt.Columns[i].ColumnName);
dataRow.GetCell(i).CellStyle = style;
}
//注释的这行是设置筛选的
//sheet.SetAutoFilter(new CellRangeAddress(0, dt.Columns.Count, 0, dt.Columns.Count));
//添加列及内容
for (int i = 0; i < dt.Rows.Count; i++)
{
dataRow = (HSSFRow)sheet.CreateRow(i + 1);
for (int j = 0; j < dt.Columns.Count; j++)
{
string ValueType = "System.String";
string Value = dt.Rows[i][j].ToString().Trim();
switch (ValueType)
{
case "System.String"://字符串类型
dataRow.CreateCell(j).SetCellValue(Value);
break;
case "System.DateTime"://日期类型
System.DateTime dateV;
System.DateTime.TryParse(Value, out dateV);
dataRow.CreateCell(j).SetCellValue(dateV);
break;
case "System.Boolean"://布尔型
bool boolV = false;
bool.TryParse(Value, out boolV);
dataRow.CreateCell(j).SetCellValue(boolV);
break;
case "System.Int16"://整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
int intV = 0;
int.TryParse(Value, out intV);
dataRow.CreateCell(j).SetCellValue(intV);
break;
case "System.Decimal"://浮点型
case "System.Double":
double doubV = 0;
double.TryParse(Value, out doubV);
dataRow.CreateCell(j).SetCellValue(doubV);
break;
case "System.DBNull"://空值处理
dataRow.CreateCell(j).SetCellValue("");
break;
case "System.Byte[]"://二进制文件
string str = System.Text.Encoding.GetEncoding("iso-8859-1").GetString((byte[])dt.Rows[i][j]);
// byte[] data = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(str);
if (str.Length < 31000)
{
dataRow.CreateCell(j).SetCellValue(str);
}
else
{
string strSub = "";
for (int n = 0; n <= str.Length / 30000; n++)
{
if (str.Length - n * 30000 - 1 >= 30000)
strSub = str.Substring(n * 30000, 30000);
if (str.Length - n * 30000 - 1 < 30000)
strSub = str.Substring(n * 30000, str.Length - n * 30000);
dataRow.CreateCell(j + n).SetCellValue(strSub);
}
}
break;
default:
dataRow.CreateCell(j).SetCellValue("");
break;
}
dataRow.GetCell(j).CellStyle = style;
// 设置宽度
sheet.SetColumnWidth(j, (Value.Length + 10) * 256);
}
}
}
workbook.Write(ms);
FileStream file = new FileStream(saveFileName, FileMode.Create);
workbook.Write(file);
file.Close();
}
}
}
我们可以借助这个类,然后实现单文件单表格导出:
这个方法里面是直接使用datagridview作为导出的数据源,然后直接调用help.ExportExcel(fileName, this.dataGridView1, "宋体", 11);进行导出,导出结果就是一个excel文件里面只含有一个名为weight的sheet。数据为datagridview中的数据。当然,这里也可以把datagridview换成datatable,然后把ExportExcel方法稍微调整即可。
private void sfbtn_Click(object sender, EventArgs e)
{
try
{
ExcelHelp help = new ExcelHelp();
string fileName = "";
if (cbsf.SelectedIndex == -1)
{
MessageBox.Show("请选择院系");
}
else
{
string sf = this.cbsf.SelectedItem.ToString();
fileName = sf + "学生成绩信息";
help.ExportExcel(fileName, this.dataGridView1, "宋体", 11);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
当然了,也可以实现单文件多表格导出:
为了实现一次性导出多个sheet,我将SaveFileDialog代码提取到ExportExcel2外面,然后调用ExportExcel2方法在一个文件中创建多个sheet,完成导出。我这里是将多个datatable放在dic中,因为我还要传递sheet名,如果不需要特定的名字,那么使用dataset来存储多个datatable也是不错的选择。同样的,这里也可以把ExportExcel2的参数改成dic里面放置datagridview,也只需要稍作调整即可。
private void allbtn_Click(object sender, EventArgs e)
{
try
{
ExcelHelp help = new ExcelHelp();
string fileName = "所有省份成绩信息表";
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.DefaultExt = "xls";
saveDialog.Filter = "Excel文件|*.xls";
saveDialog.FileName = fileName;
MemoryStream ms = new MemoryStream();
if (saveDialog.ShowDialog() == DialogResult.OK)
{
string saveFileName = saveDialog.FileName;
if (!help.CheckFiles(saveFileName))
{
MessageBox.Show("文件被占用,请关闭文件 " + saveFileName);
ms.Close();
ms.Dispose();
return;
}
Dictionary<string, DataTable> dic = new Dictionary<string, DataTable>();
for (int i = 0; i < sfList.Count; i++)
{
string sf = sfList[i];
DataTable dt = getDtBySf(sf);
if (dt.Rows.Count > 0)
{
dic.Add(sf,dt);
}
}
if (dic.Keys.Count>0)
{
help.ExportExcel2(ms, dic, "宋体", 11, saveFileName);
ms.Close();
ms.Dispose();
MessageBox.Show("文件保存成功", "提示", MessageBoxButtons.OK);
}
else
{
MessageBox.Show("没有数据可供保存!");
ms.Close();
ms.Dispose();
return;
}
}
else
{
ms.Close();
ms.Dispose();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
over!