C#,.net,winform导入Excel功能以及下载Excel文件到本地,并使用SqlBulkCopy把DataTable类型的数据写入到sqlserver数据库中

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: C#,.net,winform导入Excel功能以及下载Excel文件到本地,并使用SqlBulkCopy把DataTable类型的数据写入到sqlserver数据库中

背景


最近在项目中有一个导入Excel的功能,下文中将介绍如何在C#项目中导入Excel文件,以及实现此功能的宏观思路。


宏观思路


因为项目中的导入功能是用户根据自己的需要去导入Excel文件,那么对于用户上传的格式是有要求的。所以需要让用户先下载我们提供的模板,然后用户可以去编辑模板,再进行上传。


下载模板


下载功能是的数据类型是使用的DataTable,也就是我们在DataTable中为用户提供列的名称放在一个DataTable中,让用户去下载。


具体代码实现


通过我们在代码中设置列的标题(或者让用户可配置),已list集合的方式传入此方法中


/// <summary>
        /// 定义导入数据的模板
        /// 通过for循环给空白的DataTable添加列名称
        /// </summary>
        /// <param name="ColumnNames">模板的列的集合</param>
        /// <returns></returns>
        public DataTable ImportTemplate(List<string> ColumnNames)
        {
            DataTable template = new DataTable();
            DataRow dr = template.NewRow() ;
            template.Rows.Add(dr);
            for(int i = 0; i < ColumnNames.Count; i++)
            {
                template.Columns.Add(ColumnNames[i]);
            }
            return template;
        }


导出文件的具体代码


public void Export(DataTable dtSource,string FileName)
        {
            try {
                SaveFileDialog fileDialog = new SaveFileDialog();
                fileDialog.Filter = "Excel|*.xls|TXT|*.txt|PDF|*.pdf";
                fileDialog.FileName = FileName+"-"+DateTime.Now.ToString("D");
                if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                {
                    return;
                }
                string FileSavePath = fileDialog.FileName;
                switch (fileDialog.FilterIndex)
                {
                    case 1:
                        ExportXls(FileSavePath, dtSource); //导出xls
                        break;
                    case 2:
                        ExportTxt(FileSavePath, dtSource); //导出txt
                        break;
                    case 3:
                        ExportPDF(FileSavePath, dtSource); //导出pdf
                        break;
                        //case 4:
                        //    ExportDocx(FileSavePath, dtSource); //导出docx
                        //    break;
                }
                MessageBox.Show("文件 "+ FileSavePath + " 导出成功");
            }
            catch(Exception e){
                MessageBox.Show("导出文件失败,请稍后重新尝试"+ e);
            }
        }


有了以上两个方法之后,我们可以在某事件中去触发此这些方法,然后下载文件到用户的本地。


导入文件


上文中已经把导入的下载模板的工作完成,接下来是需要用把编辑好的Excel文件上传到我们程序并同步到数据库中。


上传Excel这里使用的NPOI,在“管理NuGet程序包”中,搜索NPOI找到,下载并安装。


ce52ba8128cff5a1c74446d4902c8222_f4c7e405704a454c805c47d4cb00d446.png


这里可能出现问题是


2f14a6f6928507b6f5b347004ce78d82_a078d692ecae4a109550adf8e60e5f4b.png


解决办法:先安装“SixLabors.Fonts”,需要注意的是:如果直接搜索的话可能找不到,需要把“包括预发行版”勾选上


0764cf17d3edcb09488a3da2460845f4_02b436b9cc0f4065bcb675adc7ffbf50.png


安装好之后,再去下载NPOI。


在项目中添加类ExcelHelper


internal class ExcelHelper
    {
        /// <summary>
        /// 从Excel读取数据,只支持单表
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        public static DataTable ReadFromExcel(string FilePath)
        {
            IWorkbook wk = null;
            string extension = System.IO.Path.GetExtension(FilePath); //获取扩展名
            try
            {
                using (FileStream fs = File.OpenRead(FilePath))
                {
                    if (extension.Equals(".xls")) //2003
                    {
                        wk = new HSSFWorkbook(fs);
                    }
                    else                         //2007以上
                    {
                        wk = new XSSFWorkbook(fs);
                    }
                }
                //读取当前表数据
                ISheet sheet = wk.GetSheetAt(0);
                //构建DataTable
                IRow row = sheet.GetRow(0);
                DataTable result = BuildDataTable(row);
                if (result != null)
                {
                    if (sheet.LastRowNum >= 1)
                    {
                        for (int i = 1; i < sheet.LastRowNum + 1; i++)
                        {
                            IRow temp_row = sheet.GetRow(i);
                            if (temp_row == null) { continue; }//2019-01-14 修复 行为空时会出错
                            List<object> itemArray = new List<object>();
                            for (int j = 0; j < result.Columns.Count; j++)//解决Excel超出DataTable列问题    lqwvje20181027
                            {
                                //itemArray.Add(temp_row.GetCell(j) == null ? string.Empty : temp_row.GetCell(j).ToString());
                                itemArray.Add(GetValueType(temp_row.GetCell(j)));//解决 导入Excel  时间格式问题  lqwvje 20180904
                            }
                            result.Rows.Add(itemArray.ToArray());
                        }
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        /// <summary>
        /// 从Excel读取数据,支持多表
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        public static DataSet ReadFromExcels(string FilePath)
        {
            DataSet ds = new DataSet();
            IWorkbook wk = null;
            string extension = System.IO.Path.GetExtension(FilePath); //获取扩展名
            try
            {
                using (FileStream fs = File.OpenRead(FilePath))
                {
                    if (extension.Equals(".xls")) //2003
                    {
                        wk = new HSSFWorkbook(fs);
                    }
                    else                         //2007以上
                    {
                        wk = new XSSFWorkbook(fs);
                    }
                }
                int SheetCount = wk.NumberOfSheets;//获取表的数量
                if (SheetCount < 1)
                {
                    return ds;
                }
                for (int s = 0; s < SheetCount; s++)
                {
                    //读取当前表数据
                    ISheet sheet = wk.GetSheetAt(s);
                    //构建DataTable
                    IRow row = sheet.GetRow(0);
                    if (row == null) { continue; }
                    DataTable tempDT = BuildDataTable(row);
                    tempDT.TableName = wk.GetSheetName(s);
                    if (tempDT != null)
                    {
                        if (sheet.LastRowNum >= 1)
                        {
                            for (int i = 1; i < sheet.LastRowNum + 1; i++)
                            {
                                IRow temp_row = sheet.GetRow(i);
                                if (temp_row == null) { continue; }//2019-01-14 修复 行为空时会出错
                                List<object> itemArray = new List<object>();
                                for (int j = 0; j < tempDT.Columns.Count; j++)//解决Excel超出DataTable列问题    lqwvje20181027
                                {
                                    itemArray.Add(GetValueType(temp_row.GetCell(j)));//解决 导入Excel  时间格式问题  lqwvje 20180904
                                }
                                tempDT.Rows.Add(itemArray.ToArray());
                            }
                        }
                        ds.Tables.Add(tempDT);
                    }
                }
                return ds;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        /// <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, string fileName, bool isColumnWritten = true)
        {
            IWorkbook workbook = null;
            using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                if (fileName.IndexOf(".xlsx") > 0) // 2007版本
                {
                    workbook = new XSSFWorkbook();
                }
                else if (fileName.IndexOf(".xls") > 0) // 2003版本
                {
                    workbook = new HSSFWorkbook();
                }
                if (workbook == null) { return -1; }
                try
                {
                    ISheet sheet = workbook.CreateSheet(sheetName);
                    int count = 0;
                    if (isColumnWritten) //写入DataTable的列名
                    {
                        IRow row = sheet.CreateRow(0);
                        for (int j = 0; j < data.Columns.Count; ++j)
                        {
                            row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName);
                        }
                        count = 1;
                    }
                    for (int i = 0; i < data.Rows.Count; ++i)
                    {
                        IRow row = sheet.CreateRow(count);
                        for (int j = 0; j < data.Columns.Count; ++j)
                        {
                            row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());
                        }
                        count++;
                    }
                    workbook.Write(fs,true); //写入到excel
                    return count;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                    return -1;
                }
            }
        }
        /// <summary>
        /// 将DataSet数据导入到excel中   每个datatable一个sheet,sheet名为datatable名
        /// </summary>
        /// <param name="ds">要导入的数据</param>
        /// <param name="isColumnWritten">DataTable的列名是否要导入</param>
        /// <param name="fileName">导出的文件途径</param>
        public static bool DataTableToExcel(DataSet ds, string fileName, bool isColumnWritten = true)
        {
            if (ds == null || ds.Tables.Count < 1)
            {
                return false;
            }
            IWorkbook workbook = null;
            using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                if (fileName.IndexOf(".xlsx") > 0) // 2007版本
                {
                    workbook = new XSSFWorkbook();
                }
                else if (fileName.IndexOf(".xls") > 0) // 2003版本
                {
                    workbook = new HSSFWorkbook();
                }
                if (workbook == null) { return false; }
                try
                {
                    foreach (DataTable dt in ds.Tables)
                    {
                        ISheet sheet = workbook.CreateSheet(dt.TableName);
                        if (isColumnWritten) //写入DataTable的列名
                        {
                            IRow row = sheet.CreateRow(0);
                            for (int j = 0; j < dt.Columns.Count; ++j)
                            {
                                row.CreateCell(j).SetCellValue(dt.Columns[j].ColumnName);
                            }
                        }
                        for (int i = 0; i < dt.Rows.Count; ++i)
                        {
                            IRow row = sheet.CreateRow(isColumnWritten ? i + 1 : i);
                            for (int j = 0; j < dt.Columns.Count; ++j)
                            {
                                row.CreateCell(j).SetCellValue(dt.Rows[i][j].ToString());
                            }
                        }
                    }
                    workbook.Write(fs,true); //写入到excel
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                    return false;
                }
            }
            return true;
        }
        private static DataTable BuildDataTable(IRow Row)
        {
            DataTable result = null;
            if (Row.Cells.Count > 0)
            {
                result = new DataTable();
                for (int i = 0; i < Row.LastCellNum; i++)
                {
                    if (Row.GetCell(i) != null)
                    {
                        result.Columns.Add(Row.GetCell(i).ToString());
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// 获取单元格类型
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private static object GetValueType(ICell cell)
        {
            if (cell == null)
                return null;
            switch (cell.CellType)
            {
                case CellType.Blank: //BLANK:  
                    return null;
                case CellType.Boolean: //BOOLEAN:  
                    return cell.BooleanCellValue;
                case CellType.Numeric: //NUMERIC:  
                    if (DateUtil.IsCellDateFormatted(cell))
                    {
                        return cell.DateCellValue;
                    }
                    return cell.NumericCellValue;
                case CellType.String: //STRING:  
                    return cell.StringCellValue;
                case CellType.Error: //ERROR:  
                    return cell.ErrorCellValue;
                case CellType.Formula: //FORMULA:  
                    cell.SetCellType(CellType.String);
                    return cell.StringCellValue;
                default:
                    return "=" + cell.CellFormula;
            }
        }
    }


在winform的中某触发事件中代码,调用刚刚的ExcelHelper对象,(这里还可以返回一个DataTable对象)


private void ExcelFile()
        {
            OpenFileDialog openFile = new OpenFileDialog();
            if (openFile.ShowDialog() == DialogResult.OK)
            {
                string filePath = openFile.FileName;
//获取本地的Excel文件
                DataTable excelDt = ExcelHelper.ReadFromExcel(filePath);
            }
        }

需要注意的是,在导入的时候如果有空白行的话,会把空白行也插入到数据库中,所以在读取本地的Excel数据之后,需要把空白行也去除掉。


List<DataRow> removelist = new List<DataRow>();
                    for (int i = 0; i < excelDt.Rows.Count; i++)
                    {
                        bool IsNull = true;
                        for (int j = 0; j < excelDt.Columns.Count; j++)
                        {
                            if (!string.IsNullOrEmpty(excelDt.Rows[i][j].ToString().Trim()))
                            {
                                IsNull = false;
                            }
                        }
                        if (IsNull)
                        {
                            removelist.Add(excelDt.Rows[i]);
                        }
                    }
                    for (int i = 0; i < removelist.Count; i++)
                    {
                        excelDt.Rows.Remove(removelist[i]);
                    }


到这里以上的操作步骤是获取本地的Excel数据了,那么接下来就可以去写入数据库中,需要注意的是:读取的数据,需要和数据库中的字段一一对应,也就是位置、名称都要对应上才行。


开发中遇到的问题:


1、用户需要提供的数据和数据库少于数据库中的字段,比如:用户需要提供姓名、手机号这两个字段,但是数据库中还需要有地址这个字段,那怎么办呢?我们可以在代码中给把这些信息补全。再写入数据库中。


示例代码


ProductTable.Columns.Add("creator");
                        ProductTable.Columns["creator"].SetOrdinal(26);//在第26列插入字段
ProductTable.Columns.Add("create_time");
                        ProductTable.Columns["create_time"].SetOrdinal(27);

2、在写数据库时,遇到数据类型不匹配。因为从本地获取的Excel数据基本上是string类型,那么数据库中有写字段是bool类型或者其他,如果插库的话就会报错,我这里解决这个问题的思路大概是在代码中把类型给转换一下,这样插入数据库时就不会出错了。


解决思路:比较笨的办法是把获取本地的数据(存放到了DataTable对象中)克隆出来一份,在克隆出来的那份中进行数据转换,因为在原来的数据不能进行转换,而且这里克隆不会把原来的数据进行克隆,所以在完成数据类型转换之后,还要把旧表中的数据同步到克隆出来的表中。


示例代码:


表克隆:


DataTable NewTable = new DataTable();
                        NewTable = ProductTable.Clone();//把原来的表进行克隆

修改类型:


//把新表中的表结构进行修改数据类型,和数据库中表字段进行保持一致
                        foreach (DataColumn col in NewTable.Columns)
                        {
                            #region ifelse
                            if (col.ColumnName == "conveyor_sel")
                            {
                                col.DataType = typeof(int);
                            }
                            else if (col.ColumnName == "p_length")
                            {
                                col.DataType = typeof(int);
                            }
                            else if (col.ColumnName == "p_width")
                            {
                                col.DataType = typeof(int);
                            }
}

旧表中的数据同步到新表中


foreach (DataRow item in ProductTable.Rows)
                            {
                                DataRow NewDtRow = NewTable.NewRow();
                                //获取对应行的产品代码的值
                                data = item.ItemArray[0];
                                NewDtRow["recipe"] = item["recipe"].ToString();
                                NewDtRow["p_name"] = item["p_name"].ToString();
                                NewDtRow["cust_name"] = item["cust_name"].ToString();
                                NewDtRow["cust_abbr"] = item["cust_abbr"].ToString();
                                NewDtRow["cust_field"] = item["cust_field"].ToString();
}


3、读取到本地Excel表中的的列标题是中文,但是数据库的形式是英文。这里也是用代码转换


示例代码:


ProductTable.Columns["产品代码"].ColumnName = "recipe";
                        ProductTable.Columns["产品名称"].ColumnName = "p_name";


使用SqlBulkCopy,把DataTable的数据写入数据库


这里用的EF框架。


public long AddDataTable(DataTable dt, String TableName)
        {
            PmsTestEntities db = new PmsTestEntities();
            SqlBulkCopy copy = new SqlBulkCopy(db.Database.Connection.ConnectionString, SqlBulkCopyOptions.UseInternalTransaction);//把本地文件复制
            copy.BatchSize = 100;//每次传输行数
            copy.NotifyAfter = dt.Rows.Count;//传输多少行后提示
            copy.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
            copy.DestinationTableName = TableName;//表名
            copy.WriteToServer(dt);
            return DataIncoming;
        }
//显示传入了多少的数据
private void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
        {
            long count = e.RowsCopied;
            DataIncoming = count;
        }

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
相关文章
|
20天前
|
Python
按条件将Excel文件拆分到不同的工作表
使用Python的pandas库,可以轻松将Excel文件按条件拆分到不同的工作表中。本文通过一个示例代码展示了如何生成一个包含总成绩表和三个班级表的Excel文件。代码首先创建了一个包含学生姓名、班级和各科成绩的数据框,然后按班级分组,将每个班级的数据分别写入不同的工作表。最后,生成的Excel文件将包含四个工作表,分别为总成绩表和三个班级的成绩表。
27 6
按条件将Excel文件拆分到不同的工作表
|
19天前
|
Python
批量将不同的工作簿合并到同一个Excel文件
本文介绍如何使用Python的`pandas`库批量合并不同工作簿至同一Excel文件。通过模拟生成三个班级的成绩数据,分别保存为Excel文件,再将这些文件合并成一个包含所有班级成绩的总成绩单。步骤包括安装必要库、生成数据、保存与合并工作簿。
28 6
|
19天前
|
Python
按条件将Excel文件拆分到不同的工作表
使用Python的pandas库,可以轻松将Excel文件按条件拆分为多个工作表。本文通过一个具体示例,展示了如何根据学生班级将成绩数据拆分到不同的工作表中,并生成一个包含总成绩表和各班级成绩表的Excel文件。代码简洁明了,适合初学者学习和应用。
32 6
|
28天前
|
前端开发
实现Excel文件和其他文件导出为压缩包,并导入
实现Excel文件和其他文件导出为压缩包,并导入
29 1
|
1月前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
57 4
|
2月前
|
JavaScript 前端开发 数据处理
Vue导出el-table表格为Excel文件的两种方式
Vue导出el-table表格为Excel文件的两种方式
101 6
|
3月前
|
SQL C# 数据库
EPPlus库的安装和使用 C# 中 Excel的导入和导出
本文介绍了如何使用EPPlus库在C#中实现Excel的导入和导出功能。首先,通过NuGet包管理器安装EPPlus库,然后提供了将DataGridView数据导出到Excel的步骤和代码示例,包括将DataGridView转换为DataTable和使用EPPlus将DataTable导出为Excel文件。接着,介绍了如何将Excel数据导入到数据库中,包括读取Excel文件、解析数据、执行SQL插入操作。
EPPlus库的安装和使用 C# 中 Excel的导入和导出
|
2月前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。
|
2月前
|
数据处理 Python
Python 高级技巧:深入解析读取 Excel 文件的多种方法
在数据分析中,从 Excel 文件读取数据是常见需求。本文介绍了使用 Python 的三个库:`pandas`、`openpyxl` 和 `xlrd` 来高效处理 Excel 文件的方法。`pandas` 提供了简洁的接口,而 `openpyxl` 和 `xlrd` 则针对不同版本的 Excel 文件格式提供了详细的数据读取和处理功能。此外,还介绍了如何处理复杂格式(如合并单元格)和进行性能优化(如分块读取)。通过这些技巧,可以轻松应对各种 Excel 数据处理任务。
251 16
|
2月前
|
JSON 数据格式
LangChain-20 Document Loader 文件加载 加载MD DOCX EXCEL PPT PDF HTML JSON 等多种文件格式 后续可通过FAISS向量化 增强检索
LangChain-20 Document Loader 文件加载 加载MD DOCX EXCEL PPT PDF HTML JSON 等多种文件格式 后续可通过FAISS向量化 增强检索
135 2

热门文章

最新文章