C#利用NPOI在Dgv控件中编辑已有的Excel并保存到Excel文件,以及NPOI 帮助类分享

该文章介绍了如何使用C#编程语言结合NPOI库来实现Excel文件与DGV控件之间的交互,包括从Excel加载数据到DGV显示,以及用户在DGV中修改数据后保存回Excel文件的操作。NpoiHelper是一个辅助类,提供了将DataTable导入Excel和从Excel导出到DataTable的方法。
摘要由CSDN通过智能技术生成

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();
                }
            }
           
        }
    }

}

尊重原创, 转载请标明出处: https://blog.csdn.net/zylgxt?type=blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Python Excellent

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值