专栏首页追逐时光.Net之Nopi Excel数据导出和批量导入功能

.Net之Nopi Excel数据导出和批量导入功能

一、介绍NPOI和编写demo的原因

Npoi是什么:

  它是一个专门用于读写Microsoft Office二进制和OOXML文件格式的.NET库,我们使用它能够轻松的实现对应数据的导入,导出功能,并且还能通过其对应的属性对Excel进行对应的样式调整。是一个简洁而又强大的第三方库。

编写该demo的原因:

  首先是为了巩固自己,其次是为了帮助一些刚开始接触的开发者更快的了解该库的操作原理。并且很多开发者在使用npoi进行大量数据导入的时候经常会遇到数据操作时间过长问题,不知道如何优化的。其实这样优化导入的方式有很多,不过一般为了提高效率都会使用T-sql进行数据批量的导入,大家需要优化导入的话可以参考下邹大佬的(http://www.cnblogs.com/jiekzou/p/6145550.html)这篇博客写的非常的详细,而我在这次使用的是EF 的 AddRange 批量插入,并且是用来layui前端框架进行了相应的布局,该demo已上传到了我的github中,需要的可以下载,地址会在文章结尾奉上。

二、导入带出的功能实现和逻辑代码展示

首先看看界面效果:

首先通过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;
        }

    }
}

三、总结

  其实做任何东西我们都需要总结和积累,首先通过自己的搜索然后参考各位网上前辈的经验然后再根据自己的理解去写。其实没有什么事情是通过自己的努力解决不了的,解决不了就是说明你还不够努力,就像我做的导入就是一次导入五六十万的数据,通过查阅了一些大佬的经验最终将导入速度优化到了比较理想的结果,当然这里我只是写了一个完整的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%8B

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux Centos上安装 MySQL 8.0.16

      因为我在我的Linux上安装的是Centos系统,本次安装对于我们这些不太熟悉Liunx操作系统的小白使用的是镜像下载安装,这样子我们只需要输入一些简单的命...

    追逐时光
  • .NET Core使用NPOI导出复杂,美观的Excel详解

      这段时间一直专注于数据报表的开发,当然涉及到相关报表的开发数据导出肯定是一个不可避免的问题啦。客户要求要导出优雅,美观的Excel文档格式的来展示数据,当时...

    追逐时光
  • .Net之微信小程序获取用户UnionID

      在实际项目开发中我们经常会遇到账号统一的问题,如何在不同端或者是不同的登录方式下保证同一个会员或者用户账号唯一(便于用户信息的管理)。这段时间就有一个这样的...

    追逐时光
  • C#生成二维码,裁切边框

    使用google zxing生成的二维码带有白色边框,显示在报告(使用Crystal Report 水晶报表)上时,由于空间有限造成二维码过小难以扫描识别。 通...

    用户1637609
  • HDU----(2157)How many ways??(快速矩阵幂)

    How many ways?? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32...

    Gxjun
  • LeetCode 5354. 通知所有员工所需的时间(迭代)

    题目链接:https://leetcode-cn.com/problems/time-needed-to-inform-all-employees/

    Ch_Zaqdt
  • 14:Challenge 7(map大法好)

    总时间限制: 10000ms单个测试点时间限制: 1000ms内存限制: 262144kB描述 给一个长为N的数列,有M次操作,每次操作是以下两种之一: (1)...

    attack
  • 程序员面试金典 - 面试题 05.08. 绘制直线(位运算)

    绘制直线。有个单色屏幕存储在一个一维数组中,使得32个连续像素可以存放在一个 int 里。 屏幕宽度为w,且w可被32整除(即一个 int 不会分布在两行上)...

    Michael阿明
  • Linux下使用crontab定时备份MYSQL数据库

    AlicFeng
  • LOJ#6279. 数列分块入门 3

    内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 1 测试数据 ...

    attack

扫码关注云+社区

领取腾讯云代金券