惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
L
LangChain Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
D
Docker
WordPress大学
WordPress大学
J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MongoDB | Blog
MongoDB | Blog
博客园 - Franky

博客园 - ssnice

AI使用总结 常见问题汇总 mysql出现 You can't specify target table 'xx' for update in FROM clause 0.000 sec 常见linux命令 nlog sqlserver 定时自动备份 sqlserver 常见语法 mysql 常用命令(linux) mysql 连接数 最大并发数 windows mysql 主从同步 mysql基础语法 windows mysql8 安装 VS2022安装后,使用VS2019打开项目,出现无法找到.NET SDK的问题解决 Asp .Net Mvc5 缓存 DataBase First创建数据库 Linq/List/Array/IEnumerable等集合操作 js中substring/substr和C#中Substring的用法 Code First研究学习2_基本的错误及解决方法 C#中静态构造函数含义及使用
OpenXML_导入Excel到数据库
ssnice · 2015-11-16 · via 博客园 - ssnice

(1).实现功能:通过前台选择.xlsx文件的Excel,将其文件转化为DataTable和List集合

(2).开发环境:Window7旗舰版+vs2013+Mvc4.0

(2).在使用中需要用到的包和dll

  1.用NuGet引入OpenXML包【全名叫DocumentFormat.OpenXml】=》注意:现在导入的Excel只支持.xlsx结尾的Excel,若导入.xls结尾的则会出现【文件包含损坏的数据】的错误!

  2.WindowsBase.dll

(3).MVC中通过file选择文件并用submit提交到Controller方法如下:

    3.1:前台代码

  <form action="Home/FileUpload" method="post" enctype="multipart/form-data">
      <div style="width:100%;height:auto;background-color:#808080">
          <input id="uploadfile" type="file" name="file" />
          <input type="submit" value="上传Excel" />
      </div>
  </form>

    3.2:Controller代码

        /// <summary>
        /// form提交回的Action
        /// </summary>
        /// <returns></returns>
        public ActionResult FileUpload()
        {
            //1.假设选择一个Excel文件  获取第一个Excel文件
            var stream = Request.Files[0].InputStream;
            //2.将选择的文件转换为DataTable
            var rst = new StreamToDataTable().ReadExcel(stream);
            //3.将DataTable转换为List集合
            var list = this.TableToLists(rst);
            return View();
        }
        /// <summary>
        /// 加载Excel数据
        /// </summary>
        public List<ExcelImport> TableToLists(System.Data.DataTable table)
        {
            TBToList<ExcelImport> tables = new TBToList<ExcelImport>();
            var lists = tables.ToList(table);
            return lists;
        }

(4).Excel流组织成Datatable方法实现

 public class StreamToDataTable
    {
        /// <summary>
        /// Excel流组织成Datatable
        /// </summary>
        /// <param name="stream">Excel文件流</param>
        /// <returns>DataTable</returns>
        public DataTable ReadExcel(Stream stream)
        {
            using (SpreadsheetDocument document = SpreadsheetDocument.Open(stream, false))     //若导入.xls格式的Excel则会出现【文件包含损坏的数据】的错误!
            {
                //打开Stream
                IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>();
                if (sheets.Count() == 0)
                {//找出符合条件的sheet,没有则返回
                    return null;
                }

                WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id);
                //获取Excel中共享数据
                SharedStringTable stringTable = document.WorkbookPart.SharedStringTablePart.SharedStringTable;
                IEnumerable<Row> rows = worksheetPart.Worksheet.Descendants<Row>();//得到Excel中得数据行

                DataTable dt = new DataTable("Excel");
                //因为需要将数据导入到DataTable中,所以我们假定Excel的第一行是列名,从第二行开始是行数据
                foreach (Row row in rows)
                {
                    if (row.RowIndex == 1)
                    {
                        //Excel第一行为列名
                        GetDataColumn(row, stringTable, ref dt);
                    }
                    GetDataRow(row, stringTable, ref dt);//Excel第二行同时为DataTable的第一行数据
                }
                return dt;
            }
        }


        /// <summary>
        /// 根据给定的Excel流组织成Datatable
        /// </summary>
        /// <param name="stream">Excel文件流</param>
        /// <param name="sheetName">需要读取的Sheet</param>
        /// <returns>组织好的DataTable</returns>
        public DataTable ReadExcelBySheetName(string sheetName, Stream stream)
        {
            using (SpreadsheetDocument document = SpreadsheetDocument.Open(stream, false))
            {//打开Stream
                IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName);
                if (sheets.Count() == 0)
                {//找出符合条件的sheet,没有则返回
                    return null;
                }

                WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id);

                //获取Excel中共享数据
                SharedStringTable stringTable = document.WorkbookPart.SharedStringTablePart.SharedStringTable;
                IEnumerable<Row> rows = worksheetPart.Worksheet.Descendants<Row>();//得到Excel中得数据行

                DataTable dt = new DataTable("Excel");
                //因为需要将数据导入到DataTable中,所以我们假定Excel的第一行是列名,从第二行开始是行数据
                foreach (Row row in rows)
                {
                    if (row.RowIndex == 1)
                    {
                        //Excel第一行为列名
                        GetDataColumn(row, stringTable, ref dt);
                    }
                    GetDataRow(row, stringTable, ref dt);//Excel第二行同时为DataTable的第一行数据
                }
                return dt;
            }
        }

        /// <summary>
        /// 构建DataTable的列
        /// </summary>
        /// <param name="row">OpenXML定义的Row对象</param>
        /// <param name="stringTablePart"></param>
        /// <param name="dt">需要返回的DataTable对象</param>
        /// <returns></returns>
        public void GetDataColumn(Row row, SharedStringTable stringTable, ref DataTable dt)
        {
            DataColumn col = new DataColumn();
            foreach (Cell cell in row)
            {
                string cellVal = GetValue(cell, stringTable);
                col = new DataColumn(cellVal);
                dt.Columns.Add(col);
            }
        }

        /// <summary>
        /// 构建DataTable的每一行数据,并返回该Datatable
        /// </summary>
        /// <param name="row">OpenXML的行</param>
        /// <param name="stringTablePart"></param>
        /// <param name="dt">DataTable</param>
        private void GetDataRow(Row row, SharedStringTable stringTable, ref DataTable dt)
        {
            // 读取算法:按行逐一读取单元格,如果整行均是空数据
            // 则忽略改行(因为本人的工作内容不需要空行)-_-
            DataRow dr = dt.NewRow();
            int i = 0;
            int nullRowCount = i;
            foreach (Cell cell in row)
            {
                string cellVal = GetValue(cell, stringTable);
                if (cellVal == string.Empty)
                {
                    nullRowCount++;
                }
                dr[i] = cellVal;
                i++;
            }
            if (nullRowCount != i)
            {
                dt.Rows.Add(dr);
            }
        }


        /// <summary>
        /// 获取单元格的值
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="stringTablePart"></param>
        /// <returns></returns>
        private string GetValue(Cell cell, SharedStringTable stringTable)
        {
            //由于Excel的数据存储在SharedStringTable中,需要获取数据在SharedStringTable 中的索引
            string value = string.Empty;
            try
            {
                if (cell.ChildElements.Count == 0)
                    return value;

                value = double.Parse(cell.CellValue.InnerText).ToString();

                if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
                {
                    value = stringTable.ChildElements[Int32.Parse(value)].InnerText;
                }
            }
            catch (Exception)
            {
                value = "N/A";
            }
            return value;
        }

    }

(5).Datatable组织为List方法实现

 public class TBToList<T> where T : new()
    {
        /// <summary>
        /// 获取列名集合
        /// </summary>
        private IList<string> GetColumnNames(DataColumnCollection dcc)
        {
            IList<string> list = new List<string>();
            foreach (DataColumn dc in dcc)
            {
                list.Add(dc.ColumnName);
            }
            return list;
        }

        /// <summary>
        ///属性名称和类型名的键值对集合
        /// </summary>
        private Hashtable GetColumnType(DataColumnCollection dcc)
        {
            if (dcc == null || dcc.Count == 0)
            {
                return null;
            }
            IList<string> colNameList = GetColumnNames(dcc);

            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            Hashtable hashtable = new Hashtable();
            int i = 0;
            if (properties.Length == colNameList.Count)
            {
                foreach (PropertyInfo p in properties)
                {
                    foreach (string col in colNameList)
                    {
                        if (!hashtable.Contains(col))
                        {
                            hashtable.Add(col, p.PropertyType.ToString() + i++);
                        }
                    }
                }
            }
            return hashtable;
        }

        /// <summary>
        /// DataTable转换成IList
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public List<T> ToList(DataTable dt)
        {
            if (dt == null || dt.Rows.Count == 0)
            {
                return null;
            }

            PropertyInfo[] properties = typeof(T).GetProperties();//获取实体类型的属性集合
            Hashtable hh = GetColumnType(dt.Columns);//属性名称和类型名的键值对集合
            IList<string> colNames = GetColumnNames(hh);//按照属性顺序的列名集合
            List<T> list = new List<T>();
            T model = default(T);
            foreach (DataRow dr in dt.Rows)
            {
                model = new T();//创建实体
                int i = 0;
                foreach (PropertyInfo p in properties)
                {
                    if (p.PropertyType == typeof(string))
                    {
                        p.SetValue(model, dr[colNames[i++]], null);
                    }
                    else if (p.PropertyType == typeof(int))
                    {
                        p.SetValue(model, int.Parse(dr[colNames[i++]].ToString()), null);
                    }
                    else if (p.PropertyType == typeof(DateTime))
                    {
                        p.SetValue(model, DateTime.Parse(dr[colNames[i++]].ToString()), null);
                    }
                    else if (p.PropertyType == typeof(float))
                    {
                        p.SetValue(model, float.Parse(dr[colNames[i++]].ToString()), null);
                    }
                    else if (p.PropertyType == typeof(double))
                    {
                        p.SetValue(model, double.Parse(dr[colNames[i++]].ToString()), null);
                    }
                }
                list.Add(model);
            }
            return list;
        }

        /// <summary>
        /// 按照属性顺序的列名集合
        /// </summary>
        private IList<string> GetColumnNames(Hashtable hh)
        {
            PropertyInfo[] properties = typeof(T).GetProperties();//获取实体类型的属性集合
            IList<string> ilist = new List<string>();
            int i = 0;
            foreach (PropertyInfo p in properties)
            {
                ilist.Add(GetKey(p.PropertyType.ToString() + i++, hh));
            }
            return ilist;
        }

        /// <summary>
        /// 根据Value查找Key
        /// </summary>
        private string GetKey(string val, Hashtable tb)
        {
            foreach (DictionaryEntry de in tb)
            {
                if (de.Value.ToString() == val)
                {
                    return de.Key.ToString();
                }
            }
            return null;
        }
    }

(6).既然List集合都得到了,那么导入数据到数据库中那也不是什么难事了.......