C#利用NPOI在Dgv控件中编辑已有的Excel并保存到Excel文件,以及NPOI 帮助类分享
1、Nuget包管理器添加NPOI 2.1.1.0
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
若用HSSF 时是对xls格式的文件进行操作。
若用XSSF时则是对xlsx格式的文件进行操作。
2、实例举例说明
2.1、加载Excel文件到DGV
private void btnSelectExcel_Click(object sender, EventArgs e)
{
string path = "";
if (SelectDirEx("扩展打开文件", ref path))
{
UIMessageTip.ShowOk(path);
lbExcelPath.Text = path;
//将Excel转为DataTable
DataTable dt = new DataTable();
dt = NpoiHelper.ExcelToDataTable("映射表", true, true, path);
dgv1.DataSource = dt;
}
}
/// <summary>
/// 选择文件
/// </summary>
/// <param name="desc">弹窗说明</param>
/// <param name="FilePath">返回true则path为选择文件路径</param>
/// <returns>是否选择文件</returns>
public bool SelectDirEx(string desc, ref string FilePath)
{
bool bOk = false;
using (OpenFileDialog fd = new OpenFileDialog())
{
fd.DefaultExt = ".xlsx";
fd.Filter = "XLSX文件(*.xlsx)|*.xlsx|XLS文件(*.xls)|*.xls|所有文件(*.*)|*.*";
fd.FilterIndex = 1;
fd.Title = "打开Excel文件";
if (fd.ShowDialog(null) == DialogResult.OK)
{
FilePath = fd.FileName;
bOk = true;
}
}
return bOk;
}
2.2、将修改的DGV内容更新到源文件
/// <summary>
/// 更新在界面修改的Dgv单元格值到Excel文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSaveDgvToExcel_Click(object sender, EventArgs e)
{
bool iOk = NpoiHelper.ReplaceExcel(lbExcelPath.Text, "映射表", dgv1);
if (iOk)
{
UIMessageTip.ShowOk(this, "映射表更新成功");
}
else
{
UIMessageTip.ShowError(this, $"映射表更新失败");
}
}
3、项目源码
在线修改的DGV单元格值已经写入到源文件的Excel表格中
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : UIForm
{
public Form1()
{
InitializeComponent();
}
#region TabPage2
private void btnSelectExcel_Click(object sender, EventArgs e)
{
string path = "";
if (SelectDirEx("扩展打开文件", ref path))
{
UIMessageTip.ShowOk(path);
lbExcelPath.Text = path;
//将Excel转为DataTable
DataTable dt = new DataTable();
dt = NpoiHelper.ExcelToDataTable("映射表", true, true, path);
dgv1.DataSource = dt;
}
}
/// <summary>
/// 选择文件
/// </summary>
/// <param name="desc">弹窗说明</param>
/// <param name="FilePath">返回true则path为选择文件路径</param>
/// <returns>是否选择文件</returns>
public bool SelectDirEx(string desc, ref string FilePath)
{
bool bOk = false;
using (OpenFileDialog fd = new OpenFileDialog())
{
fd.DefaultExt = ".xlsx";
fd.Filter = "XLSX文件(*.xlsx)|*.xlsx|XLS文件(*.xls)|*.xls|所有文件(*.*)|*.*";
fd.FilterIndex = 1;
fd.Title = "打开Excel文件";
if (fd.ShowDialog(null) == DialogResult.OK)
{
FilePath = fd.FileName;
bOk = true;
}
}
return bOk;
}
/// <summary>
/// 更新在界面修改的Dgv单元格值到Excel文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSaveDgvToExcel_Click(object sender, EventArgs e)
{
bool iOk = NpoiHelper.ReplaceExcel(lbExcelPath.Text, "映射表", dgv1);
if (iOk)
{
UIMessageTip.ShowOk(this, "映射表更新成功");
}
else
{
UIMessageTip.ShowError(this, $"映射表更新失败");
}
}
#endregion
}
}
4、NPOI 帮助类 NpoiHelper 分享
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
/// <summary>
/// 报告选项
/// </summary>
public struct R_ReportOption
{
public bool IsContainEnvTemperature;
public bool IsContainEnvHumidity;
public bool IsContainUserName;
public bool IsContainTestDatetime;
};
class NpoiHelper
{
/// <summary>
/// 将DataTable数据导入到excel中
/// </summary>
/// <param name="data">要导入的数据</param>
/// <param name="isColumnWritten">DataTable的列名是否要导入</param>
/// <param name="sheetName">要导入的excel的sheet的名称</param>
/// <param name="fileName">文件夹路径</param>
/// <returns>导入数据行数(包含列名那一行)</returns>
public static int DataTableToExcel(DataTable data, string sheetName, bool isColumnWritten, string fileName)
{
if (data == null)
{
return -1;
}
if (string.IsNullOrEmpty(sheetName))
{
return -1;
}
if (string.IsNullOrEmpty(fileName))
{
return -1;
}
IWorkbook workbook = null;
if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0)
{
workbook = new XSSFWorkbook();
}
else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0)
{
workbook = new HSSFWorkbook();
}
FileStream fs = null;
try
{
fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
ISheet sheet;
if (workbook != null)
{
sheet = workbook.CreateSheet(sheetName);
}
else { return -1;}
int j,count;
//写入DataTable的列名,写入单元格中
if (isColumnWritten)
{
var row = sheet.CreateRow(0);
for (j = 0; j < data.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName);
}
count = 1;
}
else
{
count = 0;
}
//遍历循环datatable具体数据项
int i;
for (i = 0; i < data.Rows.Count; ++i)
{
var row = sheet.CreateRow(count);
for (j = 0; j < data.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());
}
++count;
}
//将文件流写入到excel
workbook.Write(fs);
return count;
}
catch (IOException ioex)
{
return -1;
}
catch (Exception ex)
{
return -1;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
/// <summary>
/// 一次性将多个DataTable数据导入到excel中
/// </summary>
/// <param name="lstTables">要导入的表 </param>
/// <param name="isColumnWritten">DataTable的列名是否要导入</param>
/// <param name="fileName">文件夹路径</param>
/// <returns>导入表sheet的数量</returns>
public static int DataTableToExcel(List<DataTable> lstTables,bool isColumnWritten,string fileName)
{
if (lstTables == null)
{
return -1;
}
if (string.IsNullOrEmpty(fileName))
{
return -1;
}
IWorkbook workbook = null;
if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0)
{
workbook = new XSSFWorkbook();
}
else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0)
{
workbook = new HSSFWorkbook();
}
int sheetCount = 0;
FileStream fs = null;
try
{
fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
ISheet sheet;
if (workbook != null)
{
foreach (DataTable table in lstTables)
{
sheet = workbook.CreateSheet(table.TableName);
int j,count;
//写入DataTable的列名,写入单元格中
if (isColumnWritten)
{
var row = sheet.CreateRow(0);
for (j = 0; j < table.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(table.Columns[j].ColumnName);
}
count = 1;
}
else
{
count = 0;
}
//遍历循环datatable具体数据项
int i;
for (i = 0; i < table.Rows.Count; ++i)
{
var row = sheet.CreateRow(count);
for (j = 0; j < table.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(table.Rows[i][j].ToString());
}
++count;
}
sheetCount++;
}
//将文件流写入到excel
workbook.Write(fs);
}
return sheetCount;
}
catch (IOException ioex)
{
return -1;
}
catch (Exception ex)
{
return -1;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
/// <summary>
/// 将excel中的数据导入到DataTable中
/// </summary>
/// <param name="sheetName"> excel工作薄sheet的名称</param>
/// <param name="bIsFirstRowColumn"> 第一行是否是DataTable的列名</param>
/// <param name="bGetFirstSheetIfCannotFindSheetName">如果没有找到指定的sheet名称,是否获取第一个sheet</param>
/// <param name="fileName">文件路径</param>
/// <returns>返回的DataTable</returns>
public static DataTable ExcelToDataTable(string sheetName, bool bIsFirstRowColumn, bool bGetFirstSheetIfCannotFindSheetName ,string fileName)
{
if (string.IsNullOrEmpty(sheetName))
{
return null;//throw new ArgumentNullException(sheetName);
}
if (string.IsNullOrEmpty(fileName))
{
return null;//throw new ArgumentNullException(fileName);
}
var data = new DataTable();
IWorkbook workbook = null;
FileStream fs = null;
try
{
fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0)
{
workbook = new XSSFWorkbook(fs);
}
else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0)
{
workbook = new HSSFWorkbook(fs);
}
ISheet sheet = null;
if (workbook != null)
{
//如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet
//sheet = workbook.GetSheet(sheetName) ?? workbook.GetSheetAt(0);
sheet = workbook.GetSheet(sheetName);
if (sheet == null && bGetFirstSheetIfCannotFindSheetName)
sheet = workbook.GetSheetAt(0);
}
if (sheet == null) return data;
var firstRow = sheet.GetRow(0);
//一行最后一个cell的编号 即总的列数
int cellCount = firstRow.LastCellNum;
int startRow;
if (bIsFirstRowColumn)
{
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
var cell = firstRow.GetCell(i);
var cellValue = cell.StringCellValue;
if (cellValue == null) continue;
var column = new DataColumn(cellValue);
data.Columns.Add(column);
}
startRow = sheet.FirstRowNum + 1;
}
else
{
startRow = sheet.FirstRowNum;
}
//最后一列的标号
var rowCount = sheet.LastRowNum;
for (var i = startRow; i <= rowCount; ++i)
{
var row = sheet.GetRow(i);
//没有数据的行默认是null
if (row == null) continue;
var dataRow = data.NewRow();
for (int j = row.FirstCellNum; j < cellCount; ++j)
{
//同理,没有数据的单元格都默认是null
if (row.GetCell(j) != null)
dataRow[j] = row.GetCell(j).ToString();
}
data.Rows.Add(dataRow);
}
return data;
}
catch (IOException ioex)
{
return null;
}
catch (Exception ex)
{
return null;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
/// <summary>
/// 将dgv列表数据转换为datatable数据
/// </summary>
/// <param name="dgv">当前dgv列表对象</param>
/// <returns>datatable对象</returns>
public static DataTable GetDgvToTable(System.Windows.Forms.DataGridView dgv)
{
DataTable dt = new DataTable();
// 列强制转换
for (int count = 0; count < dgv.Columns.Count; count++)
{
System.Data.DataColumn dc = new System.Data.DataColumn(dgv.Columns[count].HeaderText.ToString());
dt.Columns.Add(dc);
}
// 循环行
for (int count = 0; count < dgv.Rows.Count; count++)
{
DataRow dr = dt.NewRow();
for (int countsub = 0; countsub < dgv.Columns.Count; countsub++)
{
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
}
dt.Rows.Add(dr);
}
return dt;
}
/// <summary>
/// 创建一个excel表,并写入数据
/// </summary>
/// <param name="filePath"></param>
public void write2excel(string filePath)
{
HSSFWorkbook wb = new HSSFWorkbook();//一个文件
HSSFSheet st = (HSSFSheet)wb.CreateSheet("Sheet1");//一个表
HSSFRow row = (HSSFRow)st.CreateRow(0);//一行
HSSFCell[] cell = new HSSFCell[31];//声明cell变量数组
for (int i = 0; i < 31; i++)
{
cell[i] = (HSSFCell)row.CreateCell(i);//实例化单元格
cell[i].SetCellValue(i + 1);//填写单元格
}
FileStream file = new FileStream(filePath, FileMode.Create);
wb.Write(file);
file.Close();
}
/// <summary>
/// 修改单元格内容
/// </summary>
/// <param name="filename"></param>
public static bool ReplaceExcel(string filename, string SheetName, DataGridView dgv )//修改单元格内容
{
if (dgv == null)
{
return false;
}
if (string.IsNullOrEmpty(filename))
{
return false;
}
FileStream fs = null;
try
{
fs = File.OpenRead(filename);
HSSFWorkbook wb = new HSSFWorkbook(fs);
fs.Close();
//将工作表读入wk,就可以关闭文件流了,下面将在内存中修改数据
HSSFSheet st = (HSSFSheet)wb.GetSheet(SheetName);//第三个Sheet为导通表
int rowcount = st.LastRowNum ;
int count = 0;
// 循环行 第0行为列标题行不进行改写
for (int irow = 1; irow < dgv.Rows.Count; irow++)
{
HSSFRow Excelrow = (HSSFRow)st.GetRow(irow);
DataGridViewRow dgvrow = dgv.Rows[irow-1];
for (int icolum = 0; icolum < dgv.Columns.Count; icolum++)
{
string dgvalue = dgvrow.Cells[icolum].Value.ToString();//读出内容
Excelrow.Cells[icolum ].SetCellValue(dgvalue);//修改后写回
}
++count;
}
if (count == rowcount)
{
fs = File.OpenWrite(filename);//以write方式打开文件,wb工作表写回
wb.Write(fs);
return true;
}
else return false;
}
catch (Exception ex)
{
return false;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
}
}