.NET之NPOI Excel數據導出和批量導入功能

1、介紹NPOI和編寫demo的緣由

Npoi是什麼:

  它是一個專門用於讀寫Microsoft Office二進制和OOXML文件格式的.NET庫,咱們使用它可以輕鬆的實現對應數據的導入,導出功能,而且還能經過其對應的屬性對Excel進行對應的樣式調整。是一個簡潔而又強大的第三方庫。html

編寫該demo的緣由:

  首先是爲了鞏固本身,其次是爲了幫助一些剛開始接觸的開發者更快的瞭解該庫的操做原理。而且不少開發者在使用npoi進行大量數據導入的時候常常會遇到數據操做時間過長問題,不知道如何優化的。其實這樣優化導入的方式有不少,不過通常爲了提升效率都會使用T-sql進行數據批量的導入,你們須要優化導入的話能夠參考下鄒大佬的(http://www.cnblogs.com/jiekzou/p/6145550.html)這篇博客寫的很是的詳細,而我在此次使用的是EF 的 AddRange 批量插入,而且是用來layui前端框架進行了相應的佈局,該demo已上傳到了個人github中,須要的能夠下載,地址會在文章結尾奉上。前端

 

2、導入、導出的功能實現和邏輯代碼展現

首先看看界面效果:

首先經過Nuget下載安裝Npoi:

 

批量導入:

        /// <summary>
        /// 數據導入
        /// </summary>
        /// <param name="FileStram"></param>
        /// <returns></returns>
        public ActionResult DataImport(HttpPostedFileBase  file)
        {
            var message="";
            int Columns = 0;
            //判斷是否提交excel文件
            var FileName = file.FileName.Split('.');
            if (file!=null&&file.ContentLength>0)
            {
                if (FileName[1]=="xls"||FileName[1]== "xlsx")
                {
                    //首先咱們須要導入數據的話第一步其實就是先把excel數據保存到本地中,而後經過Npoi封裝的方法去讀取已保存的Excel數據
                    
                    string DictorysPath=Server.MapPath("~/Content/ExcelFiles/"+ DateTime.Now.ToString("yyyyMMdd"));
                    if (!System.IO.Directory.Exists(DictorysPath))
                    {
                        System.IO.Directory.CreateDirectory(DictorysPath);
                    }

                    file.SaveAs(System.IO.Path.Combine(DictorysPath,file.FileName));

                    //將Excel數據轉化爲DataTable數據源
                    DataTable  Dt=NpoiHelper.Import(System.IO.Path.Combine(DictorysPath, file.FileName), FileName[1]);
                    List<UserInfo> list = new List<UserInfo>();

                    for (int i = 0; i < Dt.Rows.Count; i++)
                    {
                        UserInfo U = new UserInfo();
                        //從行索引從1開始,標題除外
                        U.UserName = Dt.Rows[i][0].ToString();
                        U.Sex = Dt.Rows[i][1].ToString();
                        U.Phone = Dt.Rows[i][2].ToString();
                        U.Hobby = Dt.Rows[i][3].ToString();
                        list.Add(U);
                    }

                    //數據所有添加
                    UserEntites.Set<UserInfo>().AddRange(list);
                    Columns=UserEntites.SaveChanges();
                    if (Columns>0)
                    {
                        message = "導入成功";
                    }
                    else
                    {
                        message = "導入失敗";
                    }

                }
                else
                {
                    message = "格式錯誤";
                }
            }
            else
            {
                message = "未找到須要導入的數據";
            }
            ViewBag.Columns = Columns;
            ViewBag.Message = message;
            return View();
        }

導出:

        /// <summary>
        /// 數據導出
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public JsonResult Export()
        {
            try
            {
                //導出全部數據
                var All_ListData = UserEntites.UserInfo.ToList();

                //將list 轉化爲datatable類型
                var Dt = DatabaseOpreas._.ListToDataTable(All_ListData);

                NpoiHelper.Export(Dt, "用戶信息", Server.MapPath("~/Content/Export.xls"));//這裏的路徑是須要寫入你須要保存的文件格式的,不須要建立自動檢測建立

                return Json(new {code=1,msg= "/Content/Export.xls" });
            }
            catch (Exception ex)
            {
                return Json(new {code=0,msg=ex.Message });    
            }

        }

 NPOI導入導出幫助類:

using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Utility
{
    /// <summary>
    /// NPOI操做幫助類
    /// </summary>
    public class NpoiHelper
    {
        /// <summary>  
        /// DataTable導出到Excel文件  
        /// </summary>  
        /// <param name="dtSource">源DataTable</param>  
        /// <param name="strHeaderText">表頭文本</param>  
        /// <param name="strFileName">保存位置</param>  
        public static void Export(DataTable dtSource, string strHeaderText, string strFileName)
        {
            using (MemoryStream ms = Export(dtSource, strHeaderText))
            {
                using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
                {
                    //數據填寫
                    byte[] data = ms.ToArray();
                    fs.Write(data, 0, data.Length);
                    fs.Flush();
                }
            }
        }

        /// <summary>  
        /// DataTable導出到Excel的MemoryStream  
        /// </summary>  
        /// <param name="dtSource">源DataTable</param>  
        /// <param name="strHeaderText">表頭文本</param>  
        public static MemoryStream Export(DataTable dtSource, string strHeaderText)
        {
            HSSFWorkbook workbook = new HSSFWorkbook();
            ISheet sheet = workbook.CreateSheet();

            ICellStyle dateStyle = workbook.CreateCellStyle();
            IDataFormat format = workbook.CreateDataFormat();
            dateStyle.DataFormat = format.GetFormat("yyyy-MM-dd");

            #region 取得每列的列寬(最大寬度)
            int[] arrColWidth = new int[dtSource.Columns.Count];
            foreach (DataColumn item in dtSource.Columns)
            {
                //GBK對應的code page是CP936
                arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
            }
            for (int i = 0; i < dtSource.Rows.Count; i++)
            {
                for (int j = 0; j < dtSource.Columns.Count; j++)
                {
                    int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
                    if (intTemp > arrColWidth[j])
                    {
                        arrColWidth[j] = intTemp;
                    }
                }
            }
            #endregion

            int rowIndex = 0;

            foreach (DataRow row in dtSource.Rows)
            {
                #region 新建表,填充表頭,填充列頭,樣式
                if (rowIndex == 65535 || rowIndex == 0)
                {
                    if (rowIndex != 0)
                    {
                        sheet = workbook.CreateSheet();
                    }

                    #region 表頭及樣式
                    {
                        IRow headerRow = sheet.CreateRow(0);
                        headerRow.HeightInPoints = 25;
                        headerRow.CreateCell(0).SetCellValue(strHeaderText);//第一列表頭名稱

                        ICellStyle headStyle = workbook.CreateCellStyle();
                        headStyle.Alignment = HorizontalAlignment.Center;
                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 20;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);

                        headerRow.GetCell(0).CellStyle = headStyle;

                        sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, dtSource.Columns.Count - 1));
                    }
                    #endregion


                    #region 列頭及樣式
                    {
                        //也可自定義標題名稱,填寫到 headerRow.CreateCell(1).SetCellValue();需使用directory<string,string>先填寫標題,而後遍歷操做中便可
                        IRow headerRow = sheet.CreateRow(1);
                        ICellStyle headStyle = workbook.CreateCellStyle();
                        headStyle.Alignment = HorizontalAlignment.Center;
                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 10;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);


                        foreach (DataColumn column in dtSource.Columns)
                        {
                            headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                            headerRow.GetCell(column.Ordinal).CellStyle = headStyle;

                            //設置列寬  
                            sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);

                        }
                    }
                    #endregion

                    rowIndex = 2;
                }
                #endregion


                #region 填充內容
                ICellStyle contentStyle = workbook.CreateCellStyle();
                contentStyle.Alignment = HorizontalAlignment.Left;
                IRow dataRow = sheet.CreateRow(rowIndex);
                foreach (DataColumn column in dtSource.Columns)
                {
                    ICell newCell = dataRow.CreateCell(column.Ordinal);
                    newCell.CellStyle = contentStyle;

                    string drValue = row[column].ToString();

                    switch (column.DataType.ToString())
                    {
                        case "System.String"://字符串類型  
                            newCell.SetCellValue(drValue);
                            break;
                        case "System.DateTime"://日期類型  
                            DateTime dateV;
                            DateTime.TryParse(drValue, out dateV);
                            newCell.SetCellValue(dateV);

                            newCell.CellStyle = dateStyle;//格式化顯示  
                            break;
                        case "System.Boolean"://布爾型  
                            bool boolV = false;
                            bool.TryParse(drValue, out boolV);
                            newCell.SetCellValue(boolV);
                            break;
                        case "System.Int16"://整型  
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            int intV = 0;
                            int.TryParse(drValue, out intV);
                            newCell.SetCellValue(intV);
                            break;
                        case "System.Decimal"://浮點型  
                        case "System.Double":
                            double doubV = 0;
                            double.TryParse(drValue, out doubV);
                            newCell.SetCellValue(doubV);
                            break;
                        case "System.DBNull"://空值處理  
                            newCell.SetCellValue("");
                            break;
                        default:
                            newCell.SetCellValue("");
                            break;
                    }

                }
                #endregion

                rowIndex++;
            }


            using (MemoryStream ms = new MemoryStream())
            {
                workbook.Write(ms);
                ms.Flush();
                ms.Position = 0;

                //sheet.Dispose();
                //workbook.Dispose();//通常只用寫這一個就OK了,他會遍歷並釋放全部資源,但當前版本有問題因此只釋放sheet  
                return ms;
            }

        }


        /// <summary>
        /// 讀取excel,將數據Excel數據源轉化爲datatable類型  
        /// 默認第一行爲標頭  
        /// </summary>  
        /// <param name="strFileName">excel文檔路徑</param>  
        /// <returns></returns>  
        public static DataTable Import(string strFileName,string FileType)
        {
            IWorkbook hssfworkbook;
            DataTable dt = new DataTable();

            //HSSFWorkbook hssfworkbook;
            using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read))//數據讀取
            {
                ////XSSFWorkbook 適用XLSX格式,HSSFWorkbook 適用XLS格式
                //不一樣格式excle判斷
                if (FileType == "xls")
                {
                    hssfworkbook = new HSSFWorkbook(file);
                }
                else
                {
                    hssfworkbook = new XSSFWorkbook(file);
                }
            }
            ISheet sheet = hssfworkbook.GetSheetAt(0);
            System.Collections.IEnumerator rows = sheet.GetRowEnumerator();

            IRow headerRow = sheet.GetRow(0);
            int cellCount = headerRow.LastCellNum;

            for (int j = 0; j < cellCount; j++)
            {
                ICell cell = headerRow.GetCell(j);
                dt.Columns.Add(cell.ToString());
            }

            for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
            {
                IRow row = sheet.GetRow(i);
                DataRow dataRow = dt.NewRow();

                for (int j = row.FirstCellNum; j < cellCount; j++)
                {
                    if (row.GetCell(j) != null)
                        dataRow[j] = row.GetCell(j).ToString();
                }

                dt.Rows.Add(dataRow);
            }
            return dt;
        }

    }
}

 3、總結

       其實作任何東西咱們都須要總結和積累,首先經過本身的搜索而後參考各位網上前輩的經驗而後再根據本身的理解去寫。其實沒有什麼事情是經過本身的努力解決不了的,解決不了就是說明你還不夠努力,就像我作的導入就是一次導入五六十萬的數據,經過查閱了一些大佬的經驗最終將導入速度優化到了比較理想的結果,固然這裏我只是寫了一個完整的demo,你們想要深刻研究的話就得花時間本身學了啦,最後附上項目地址:https://github.com/YSGStudyHards/ShipBuilding/tree/master/C%23%EF%BC%8C.Net%EF%BC%8C.Net%20Core%20%E7%BC%96%E7%A8%8B%E7%BB%83%E4%B9%A0/Asp.NetMVC%E4%B9%8BNpoi%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA%E5%AE%9E%E4%BE%8Bgit

相關文章
相關標籤/搜索