1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【总结】C#上传excel文件到Sql server数据库

【总结】C#上传excel文件到Sql server数据库

时间:2020-12-07 23:49:34

相关推荐

【总结】C#上传excel文件到Sql server数据库

工具 : VS + SQL Server R2

框架:三层+一般处理程序

方法:方法很多种,百度千奇百怪,总结下来更好更快的方法,以下会提到

最近接触到需要实现将一个excel表格的数据移植到数据库的需求,但此前从未接触过

百度+体会+探讨 总结下来以便后续需要使用,乐于分享给大家,望给予修正

少废话上代码

①数据库,移植到数据库肯定需要表吧,都懂不多说

②需要一个帮助类(当然自己写也可以,个人比较喜欢帮助类,即ExcelHelper类,放dal层)

一时半会可能看不懂(除了导入还有导出,挺全),c+v 懂?

另外注意,需要引用Nuget包 NOPI 使用nopi去导入导出我觉得目前自己掌握的来说最好

using System;using System.Collections.Generic;using System.Data;using System.IO;using System.Linq;using System.Text;using System.Threading.Tasks;using NPOI.SS.UserModel;using NPOI.XSSF.UserModel;using NPOI.HSSF.UserModel;namespace Customer_DAL{public class NopiExcelHelper:IDisposable{private string fileName = null; //文件名private IWorkbook workbook = null;private FileStream fs = null;private bool disposed;public NopiExcelHelper(string fileName){this.fileName = fileName;disposed = false;}/// <summary>/// 将DataTable数据导入到excel中/// </summary>/// <param name="data">要导入的数据</param>/// <param name="isColumnWritten">DataTable的列名是否要导入</param>/// <param name="sheetName">要导入的excel的sheet的名称</param>/// <returns>导入数据行数(包含列名那一行)</returns>public int DataTableToExcel(DataTable data, string sheetName, bool isColumnWritten){int i = 0;int j = 0;int count = 0;ISheet sheet = null;fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);if (fileName.IndexOf(".xlsx") > 0) // 版本workbook = new XSSFWorkbook();else if (fileName.IndexOf(".xls") > 0) // 版本workbook = new HSSFWorkbook();try{if (workbook != null){sheet = workbook.CreateSheet(sheetName);}else{return -1;}if (isColumnWritten == true) //写入DataTable的列名{IRow 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;}for (i = 0; i < data.Rows.Count; ++i){IRow row = sheet.CreateRow(count);for (j = 0; j < data.Columns.Count; ++j){row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());}++count;}workbook.Write(fs); //写入到excelreturn count;}catch (Exception ex){Console.WriteLine("Exception: " + ex.Message);return -1;}}/// <summary>/// 将excel中的数据导入到DataTable中/// </summary>/// <param name="sheetName">excel工作薄sheet的名称</param>/// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>/// <returns>返回的DataTable</returns>public DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn){ISheet sheet = null;DataTable data = new DataTable();int startRow = 0;try{fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);if (fileName.IndexOf(".xlsx") > 0) // 版本workbook = new XSSFWorkbook(fs);else if (fileName.IndexOf(".xls") > 0) // 版本workbook = new HSSFWorkbook(fs);if (sheetName != null){sheet = workbook.GetSheet(sheetName);if (sheet == null) //如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet{sheet = workbook.GetSheetAt(0);}}else{sheet = workbook.GetSheetAt(0);}if (sheet != null){IRow firstRow = sheet.GetRow(0);int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数if (isFirstRowColumn){for (int i = firstRow.FirstCellNum; i < cellCount; ++i){ICell cell = firstRow.GetCell(i);if (cell != null){string cellValue = cell.StringCellValue;if (cellValue != null){DataColumn column = new DataColumn(cellValue);data.Columns.Add(column);}}}startRow = sheet.FirstRowNum + 1;}else{startRow = sheet.FirstRowNum;}//最后一列的标号int rowCount = sheet.LastRowNum;for (int i = startRow; i <= rowCount; ++i){IRow row = sheet.GetRow(i);if (row == null) continue; //没有数据的行默认是nullDataRow dataRow = data.NewRow();for (int j = row.FirstCellNum; j < cellCount; ++j){if (row.GetCell(j) != null) //同理,没有数据的单元格都默认是nulldataRow[j] = row.GetCell(j).ToString();}data.Rows.Add(dataRow);}}return data;}catch (Exception ex){Console.WriteLine("Exception: " + ex.Message);return null;}}public void Dispose(){Dispose(true);GC.SuppressFinalize(this);}protected virtual void Dispose(bool disposing){if (!this.disposed){if (disposing){if (fs != null)fs.Close();}fs = null;disposed = true;}}}}

③Html页

此处需要说明,网上大多在上传这块使用的是Form表单请求,但是我不喜欢用,感觉不怎么好,还是ajax来得清晰

此处的ajax请求在数据传输上可能有一点不同,具体在代码备注里

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title></title><meta charset="utf-8" /><script src="Content/js/jquery-3.3.1.min.js"></script></head><body><div class="upload" style="border:1px solid;width:500px"><h4>上传数据表(上传前请注意excel表的数据格式)</h4><input type="file" name="fileUpload" id="fafafa" /><br /><input type="button" value="点击上传" class="uploadBtn" /></div><script type="text/javascript">$(function () {//上传文件到服务器$(".uploadBtn").click(function () {//获取文件对象var file_obj = document.getElementById('fafafa').files[0];//获取文件名//var filename = file_obj.name;//创建一个formData对象实例var fd = new FormData();fd.append('username', 'root');//将excel数据添加到fdfd.append('fafafa', file_obj);//传到后台文件非json数据,故此处异于一般ajax请求(json)$.ajax({url: "Handler/upload_Dom.ashx",data: fd,type: "post",//让jquery不序列化data 参数信息详见详情见 /prefect/p/5632986.html processData: false, contentType: false,success: function (data) {alert(data);}});})})</script></body></html>

④一般处理程序,个人建议与其他功能分开,单独将上传功能作为一个处理程序

eg:内附详细的备注,应该看得懂的

using Customer_DAL;using System;using System.Collections.Generic;using System.Configuration;using System.Data;using System.Data.SqlClient;using System.Diagnostics;using System.IO;using System.Linq;using System.Web;namespace Cidly_Customer_Sys.Handler{/// <summary>/// upload_Dom 的摘要说明/// </summary>public class upload_Dom : IHttpHandler{public void ProcessRequest(HttpContext context){context.Response.ContentType = "text/plain";//第①步上传文件HttpServerUtility Server = context.Server; //减轻代码量 context.Response.WriteHttpRequest Request = context.Request;HttpResponse Response = context.Response;//获得第一个文件HttpPostedFile file = context.Request.Files[0];//将上传过来的内容保存到一个文件夹string str1 = Path.GetFileName(file.FileName);//获取文件扩展名string extName = Path.GetExtension(file.FileName);//定义判断允许接受文件类型string Fileter = ".xlsx|.xls"; //|.png|.gif|.ico//重置文件名并赋值fileName为新文件名防重名(无后缀)string fileName = Guid.NewGuid().ToString();//本地保存的详细地址(得到原文件名)//string phyFilePath = context.Request.MapPath("~/Upload/Document/") + str1;//重置文件名string fullName = fileName + extName;//文件保存地址string phyFilePath = context.Request.MapPath("~/Upload/Document/") + fullName;//首先判断文件域是否有文件 + 扩展名是否在被允许的文件内if (file.ContentLength > 0 && Fileter.Contains(extName.ToLower())){//根据相对路径获取绝对路径,并追加文件名开始保存file.SaveAs(phyFilePath);//Response.Write("上传成功,上传文件名:" + fullName);//第②步 Excel转换为DataTable phyFilePath参数为excel的路径//创建NopiExcelHelper类的实例NopiExcelHelper excel = new NopiExcelHelper(phyFilePath);//转换DataTable dt = excel.ExcelToDataTable("Sheet1", true);if (dt.Rows.Count > 0){//第③步批量插入//连接数据库try{string conStr = ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;SqlConnection connection = new SqlConnection(conStr);using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conStr, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.UseInternalTransaction)){bulkCopy.DestinationTableName = "Wild_CustomerInfo";//目标表,就是说您将要将数据插入到哪个表中去bulkCopy.ColumnMappings.Add("Wild_Customer_Name", "Wild_Customer_Name");//数据源中的列名与目标表的属性的映射关系bulkCopy.ColumnMappings.Add("Wild_Customer_Sex", "Wild_Customer_Sex");bulkCopy.ColumnMappings.Add("Wild_Customer_Adress", "Wild_Customer_Adress");bulkCopy.ColumnMappings.Add("Wild_Customer_Emile", "Wild_Customer_Emile");bulkCopy.ColumnMappings.Add("Wild_Customer_wrokinfo", "Wild_Customer_wrokinfo");//DataTable dt = GetDataTableData(); //数据源数据//bulkCopy.BatchSize = 3;Stopwatch stopwatch = new Stopwatch();//跑表,该类可以进行时间的统计stopwatch.Start();//跑表开始bulkCopy.WriteToServer(dt);//将数据源数据写入到目标表中//context.Response.Write("成功插入,插入数据所用时间:" + stopwatch.Elapsed);//跑表结束,Elapsed是统计到的时间}}catch (Exception ex){context.Response.Write(ex.Message.ToString());}}}}public bool IsReusable{get{return false;}}}}

9行6列数据花的时间,可能这是一个笼统的,相对insert循环来说,快了不少

/6/13补充:

文件域的判断在后台写似乎无用,前台在无文件的情况下无法到后台,故在前台写了判断文件域是否上传了文件

另:发现一个bug 也算是已知的bug吧 此插入程序对excel的格式有一定要求,有以下问题

excel的表头需要和数据库的列名对应必须确保没有多余的行(空的但是存在的行,例如原先有数据,清除内容后而不是删除),否贼会当“”传入进去在excel关闭状态下上传

解决方案:

表的问题就不说了,全选放新表最快最准确

在excelhelpler里面暂时无法对行做判断,于是我在后台写了判断,出入数据为“”时不插入

版本所有:少废话|上代码丶 转载请声明少废话|上代码

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。