• 使用NPOI导入导出标准Excel


    尝试过很多Excel导入导出方法,都不太理想,无意中逛到oschina时,发现了NPOI,无需Office COM组件且不依赖Office,顿时惊为天人,怀着无比激动的心情写下此文。

    曾使用过的方法

    1. 直接导出html,修改后缀名为.xls,这个方法有点像骗人的把戏,而且不能再导入
    2. 使用Jet OLEDB引擎来进行导入导出,完全使用sql语句来进行操作,缺点能控制的东西非常有限,比如格式就难以控制
    3. 使用Office COM组件进行导入导出,对环境依赖性太强(如“检索 COM 类工厂…”错误);且需要通过打开Excel.exe进程进行操作;虽然可以通过关闭工作表以及Marshal.ReleaseComObject方法来释放资源,但依然避免不了性能差。

    关于NPOI

    NPOIPOI项目的.NET版本,是由@Tony Qu(http://tonyqus.cnblogs.com/)等大侠基于POI开发的,可以从http://npoi.codeplex.com/下载到它的最新版本。它不使用Office COM组件(Microsoft.Office.Interop.XXX.dll),不需要安装Microsoft Office,支持对Office 97-2003的文件格式,功能比较强大。更详细的说明请看作者的博客或官方网站。

    它的以下一些特性让我相当喜欢:

    1. 支持对标准的Excel读写
    2. 支持对流(Stream)的读写 (而Jet OLEDB和Office COM都只能针对文件)
    3. 支持大部分Office COM组件的常用功能
    4. 性能优异 (相对于前面的方法)
    5. 使用简单,易上手

    使用NPOI

    本文使用的是它当前的最新版本1.2.4,此版本的程序集缩减至2个:NPOI.dllIonic.Zip.dll,直接引用到项目中即可。

    对于我们开发者使用的对象主要位于NPOI.HSSF.UserModel空间下,主要有HSSFWorkbookHSSFSheetHSSFRowHSSFCell,对应的接口为位于NPOI.SS.UserModel空间下的IWorkbookISheetIRowICell,分别对应Excel文件、工作表、行、列。

    简单演示一下创建一个Workbook对象,添加一个工作表,在工作表中添加一行一列:

    using NPOI.HSSF.UserModel;
    using NPOI.SS.UserModel;
    
    public class NPOIWrite
    {
        void CreateSheet()
        {
            IWorkbook workbook = new HSSFWorkbook();//创建Workbook对象
            ISheet sheet = workbook.CreateSheet("Sheet1");//创建工作表
            IRow row = sheet.CreateRow(0);//在工作表中添加一行
            ICell cell = row.CreateCell(0);//在行中添加一列
            cell.SetCellValue("test");//设置列的内容
        }
    }

    相应的读取代码:

    using System.IO;
    using NPOI.HSSF.UserModel;
    using NPOI.SS.UserModel;
    
    public class NPOIRead
    {
        void GetSheet(Stream stream)
        {
            IWorkbook workbook = new HSSFWorkbook(stream);//从流内容创建Workbook对象
            ISheet sheet = workbook.GetSheetAt(0);//获取第一个工作表
            IRow row = sheet.GetRow(0);//获取工作表第一行
            ICell cell = row.GetCell(0);//获取行的第一列
            string value = cell.ToString();//获取列的值
        }
    }

    使用NPOI导出

    从DataTable读取内容来创建Workbook对象:

        public static MemoryStream RenderToExcel(DataTable table)
        {
            MemoryStream ms = new MemoryStream();
    
            using (table)
            {
                using (IWorkbook workbook = new HSSFWorkbook())
                {
                    using (ISheet sheet = workbook.CreateSheet())
                    {
                        IRow headerRow = sheet.CreateRow(0);
    
                        // handling header.
                        foreach (DataColumn column in table.Columns)
                            headerRow.CreateCell(column.Ordinal).SetCellValue(column.Caption);//If Caption not set, returns the ColumnName value
    
                        // handling value.
                        int rowIndex = 1;
    
                        foreach (DataRow row in table.Rows)
                        {
                            IRow dataRow = sheet.CreateRow(rowIndex);
    
                            foreach (DataColumn column in table.Columns)
                            {
                                dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
                            }
    
                            rowIndex++;
                        }
    
                        workbook.Write(ms);
                        ms.Flush();
                        ms.Position = 0;
                    }
                }
            }
            return ms;
        }

    如果看不惯DataTable,那么DataReader也行:

        public static MemoryStream RenderToExcel(IDataReader reader)
        {
            MemoryStream ms = new MemoryStream();
    
            using (reader)
            {
                using (IWorkbook workbook = new HSSFWorkbook())
                {
                    using (ISheet sheet = workbook.CreateSheet())
                    {
                        IRow headerRow = sheet.CreateRow(0);
                        int cellCount = reader.FieldCount;
    
                        // handling header.
                        for (int i = 0; i < cellCount; i++)
                        {
                            headerRow.CreateCell(i).SetCellValue(reader.GetName(i));
                        }
    
                        // handling value.
                        int rowIndex = 1;
                        while (reader.Read())
                        {
                            IRow dataRow = sheet.CreateRow(rowIndex);
    
                            for (int i = 0; i < cellCount; i++)
                            {
                                dataRow.CreateCell(i).SetCellValue(reader[i].ToString());
                            }
    
                            rowIndex++;
                        }
    
                        workbook.Write(ms);
                        ms.Flush();
                        ms.Position = 0;
                    }
                }
            }
            return ms;
        }

    以上代码把创建的Workbook对象保存到流中,可以通过以下方法输出到浏览器,或是保存到硬盘中:

        static void SaveToFile(MemoryStream ms, string fileName)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                byte[] data = ms.ToArray();
    
                fs.Write(data, 0, data.Length);
                fs.Flush();
    
                data = null;
            }
        }
    
        static void RenderToBrowser(MemoryStream ms, HttpContext context, string fileName)
        {
            if (context.Request.Browser.Browser == "IE")
                fileName = HttpUtility.UrlEncode(fileName);
            context.Response.AddHeader("Content-Disposition", "attachment;fileName=" + fileName);
            context.Response.BinaryWrite(ms.ToArray());
        }

    使用NPOI导入

    需要注意的是,sheet.LastRowNum = sheet.PhysicalNumberOfRows - 1,这里可能存在BUG:当没有数据或只有一行数据时sheet.LastRowNum为0,PhysicalNumberOfRows 表现正常

    这里读取流中的Excel来创建Workbook对象,并转换成DataTable:

        static DataTable RenderFromExcel(Stream excelFileStream)
        {
            using (excelFileStream)
            {
                using (IWorkbook workbook = new HSSFWorkbook(excelFileStream))
                {
                    using (ISheet sheet = workbook.GetSheetAt(0))//取第一个表
                    {
                        DataTable table = new DataTable();
    
                        IRow headerRow = sheet.GetRow(0);//第一行为标题行
                        int cellCount = headerRow.LastCellNum;//LastCellNum = PhysicalNumberOfCells
                        int rowCount = sheet.LastRowNum;//LastRowNum = PhysicalNumberOfRows - 1
    
                        //handling header.
                        for (int i = headerRow.FirstCellNum; i < cellCount; i++)
                        {
                            DataColumn column = new DataColumn(headerRow.GetCell(i).StringCellValue);
                            table.Columns.Add(column);
                        }
    
                        for (int i = (sheet.FirstRowNum + 1); i <= rowCount; i++)
                        {
                            IRow row = sheet.GetRow(i);
                            DataRow dataRow = table.NewRow();
    
                            if (row != null)
                            {
                                for (int j = row.FirstCellNum; j < cellCount; j++)
                                {
                                    if (row.GetCell(j) != null)
                                        dataRow[j] = GetCellValue(row.GetCell(j));
                                }
                            }
    
                            table.Rows.Add(dataRow);
                        }
                        return table;
    
                    }
                }
            }
        }

    或者是直接生成SQL语句来插入到数据库:

        public static int RenderToDb(Stream excelFileStream, string insertSql, DBAction dbAction)
        {
            int rowAffected = 0;
            using (excelFileStream)
            {
                using (IWorkbook workbook = new HSSFWorkbook(excelFileStream))
                {
                    using (ISheet sheet = workbook.GetSheetAt(0))//取第一个工作表
                    {
                        StringBuilder builder = new StringBuilder();
    
                        IRow headerRow = sheet.GetRow(0);//第一行为标题行
                        int cellCount = headerRow.LastCellNum;//LastCellNum = PhysicalNumberOfCells
                        int rowCount = sheet.LastRowNum;//LastRowNum = PhysicalNumberOfRows - 1
    
                        for (int i = (sheet.FirstRowNum + 1); i <= rowCount; i++)
                        {
                            IRow row = sheet.GetRow(i);
                            if (row != null)
                            {
                                builder.Append(insertSql);
                                builder.Append(" values (");
                                for (int j = row.FirstCellNum; j < cellCount; j++)
                                {
                                    builder.AppendFormat("'{0}',", GetCellValue(row.GetCell(j)).Replace("'", "''"));
                                }
                                builder.Length = builder.Length - 1;
                                builder.Append(");");
                            }
    
                            if ((i % 50 == 0 || i == rowCount) && builder.Length > 0)
                            {
                                //每50条记录一次批量插入到数据库
                                rowAffected += dbAction(builder.ToString());
                                builder.Length = 0;
                            }
                        }
                    }
                }
            }
            return rowAffected;
        }

    这里的Excel可能没有数据,所以可以加一个方法来检测:

        public static bool HasData(Stream excelFileStream)
        {
            using (excelFileStream)
            {
                using (IWorkbook workbook = new HSSFWorkbook(excelFileStream))
                {
                    if (workbook.NumberOfSheets > 0)
                    {
                        using (ISheet sheet = workbook.GetSheetAt(0))
                        {
                            return sheet.PhysicalNumberOfRows > 0;
                        }
                    }
                }
            }
            return false;
        }

    结尾

    好吧,不说啥了,放代码:点击下载

    作者:囧月
    出处:http://lwme.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Power Apps 创建响应式布局
    SharePoint Online 软件边界限制
    Power Apps 中人员选择器的使用
    Power Apps 中修改 SharePoint Online 数据
    Power Apps 中调用 Automate 工作流
    如何查看你的Office 365 账号的订阅
    Microsoft Teams 中嵌入SharePoint Online 页面
    SharePoint Online 触发Outlook邮件内审批
    Linux查看实时网卡流量的几种方式
    Linux性能优化和监控系列(三)——分析Memory使用状况
  • 原文地址:https://www.cnblogs.com/lwme/p/npoi_excel_import_export.html
Copyright © 2020-2023  润新知