使用NPOI操作Excel

Posted 守望星空的那一边

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用NPOI操作Excel相关的知识,希望对你有一定的参考价值。

  Excel表格是工作中经常用到的数据整理工具。有时候我们可能会需要把数据库中的数据导出到Excel文件中或者将Excel文件中的数据导入到数据库,如果我们使用手动方式去操作,既费时又费力,这种大量重复的工作我们可以完全使用代码编程来完成。在.net下有多种方法可以操作Excel表格,如引用com组件:Microsoft.Office.Interop.Excel.dll采用OleDB读取Excel文件,开源的EPPlus(.xlsx)等。这里为大家介绍下一使用开源的NPOI(.xls)来进行数据库的操作。

  一、什么是NPOI

  1.NPOI是指构建在POI 3.x版本之上的一个程序,NPOI可以在没有安装Office的情况下对Word或Excel文档进行读写操作。

  2.开源的项目,可以完全免费使用。

  3.NPOI支持导出Excel和导入Excel,并能“理解”OLE2文档结构。

  官网下载链接:http://npoi.codeplex.com/documentation

  二、简介NOPI

  NPOI中操作Excel常用的的类和方法

1.工作簿HSSFWorkbook

 描述工作簿的类:IWorkbook(接口),HSSFWorkbook(具体的实现类,一个HSSFWorkbook就表示了一个Excel文件,读写Excel文件都需要首先创建这个类的实例对象)
    构造方法,无参数表示创建一个新的工作本,可以接受一个流对象用于打开一个现有的工作簿
    方法CreateSheet(索引):创建指定索引的sheet对象
    方法GetSheetAt(索引):根据索引获取sheet对象
    方法CreateCellStyle();创建单元格样式对象
    方法CreateFont():创建字体对象
    方法Write(stream):将工作簿输出到流中
2.工作表HSSFSheet

 描述工作表的类ISheet(接口),HSSFSheet(具体实现类)描述工作表的类ISheet(接口),HSSFSheet(具体实现类)
    方法CreateRow(索引):创建指定索引的行
    方法GetRow(索引):根据索引获取行
    方法AddMergedRegion():设置合并区域,参数包括开始行索引,开始列索引,结束行索引,结束列索引
    方法SetColumnWidth(索引,宽度):设置指定列的宽度
    属性FirstRowNum、LastRowNum:获取第一行、最后一行的索引
3.行对象HSSFRow
    方法CreateCell(索引):创建指定索引的列
    方法GetCell(索引):根据索引获取指定列
    属性HeightInPoints:指顶或获取高度
4.单元格对象HSSFCell
    方法SetCellValue():设置单元格中的值
    属性***CellValue:获取单元格中指定类型的值如果不匹配会抛出异常
    属性CellStyle:获取或设置单元格样式
5.单元格样式对象HSSFCellStyle
    方法SetFont(字体对象):设置字体样式
    属性Alignment:水平对齐,1左,2中,3右
6.字体对象HSSFFont
    属性FontHeightInPoints:获取或设置字体大小
    属性Boldweight:获取或设置字体加粗

   三、从数据库导出数据到Excel

  1.引入dll文件(2.0和4.0的两个版本可以根据需要选用)

  2.代码

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

namespace NPOITesst
{
    class Program
    {
        static void Main(string[] args)
        {
            //从数据库中读取数据
            List<PhoneNum> phoneNums = GetAllPhoneNum();

            //保存到Excel中
            SaveToExcel(phoneNums);
            

            Console.WriteLine("OK!");
            Console.Read();
        }

        static List<PhoneNum> GetAllPhoneNum()
        {
            //数据库的简单查询,可以使用EF或者其他的微型ORM框架(代码很简单,就几行)
            List<PhoneNum> phoneNumList = new List<PhoneNum>();
            string constr = "Data source=localhost;Initial catalog=PhoneNumManager;Integrated security=true";
            string sql = "select pn.*,pt.ptName from PhoneNum as pn inner join PhoneType as pt on pn.pTypeId=pt.ptId";
            using (SqlConnection con = new SqlConnection(constr))
            {
                using (SqlCommand command = new SqlCommand(sql, con))
                {
                    con.Open();
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            while (reader.Read())
                            {
                                PhoneNum model = new PhoneNum
                                {
                                    PID = reader.GetInt32(0),
                                    PType = new PhoneType()
                                    {
                                        PTID = reader.GetInt32(1),
                                        PTName = reader.GetString(5)
                                    },
                                    PName = reader.GetString(2),
                                    PCellPhone = reader.GetString(3),
                                    PHomePhone = reader.GetString(4)
                                };
                                phoneNumList.Add(model);
                            }
                        }
                    }
                }
            }
            return phoneNumList;
        }

        static void SaveToExcel(List<PhoneNum> phoneNumList)
        {
            //1.创建工作簿对象,
            IWorkbook workBook = new HSSFWorkbook();

            //2.在工作簿中创建工作表对象
            ISheet sheet = workBook.CreateSheet("PhoneNum");

            //第一行列名
            IRow firstRow = sheet.CreateRow(0);
            firstRow.CreateCell(0).SetCellValue("序号");
            firstRow.CreateCell(1).SetCellValue("姓名");
            firstRow.CreateCell(2).SetCellValue("手机");
            firstRow.CreateCell(3).SetCellValue("固话");
            firstRow.CreateCell(4).SetCellValue("备注");

            //剩下的数据
            for (int i = 0; i < phoneNumList.Count; i++)
            {
                IRow row = sheet.CreateRow(i + 1);
                row.CreateCell(0).SetCellValue(phoneNumList[i].PID);
                row.CreateCell(1).SetCellValue(phoneNumList[i].PName);
                row.CreateCell(2).SetCellValue(phoneNumList[i].PCellPhone);
                row.CreateCell(3).SetCellValue(phoneNumList[i].PHomePhone);
                row.CreateCell(4).SetCellValue(phoneNumList[i].PType.PTName);
            }

            //文件流写入
            using (FileStream fw = File.Open("PhoneNum.xls", FileMode.OpenOrCreate, FileAccess.Write))
            {
                workBook.Write(fw);
            }

        }
    }

    class PhoneNum
    {
        public int PID { get; set; }
        public string PName { get; set; }
        public string PCellPhone { get; set; }
        public string PHomePhone { get; set; }
        public PhoneType PType { get; set; }
    }

    class PhoneType
    {
        public int PTID { get; set; }
        public string PTName { get; set; }
    }
}
View Code

 

结果图片:

  四、从Excel导入数据到数据库

  直接上代码:

  

class ExcelToDB
    {
        public static List<Person> GetAllDataFromExcel(string excelPath)
        {
            List<Person> personList = new List<Person>();
            //1.创建IWorkbook
            using (FileStream fr = File.OpenRead(excelPath))
            {
                IWorkbook wkbook = new XSSFWorkbook(fr);
                //遍历每个Sheet
                for (int i = 0; i < wkbook.NumberOfSheets; i++)
                {   //获取每个Sheet对象
                    ISheet sheet = wkbook.GetSheetAt(i);

                    //获取每个工作表中的行
                    //第一行是列名舍去,从第二行开始读取
                    for (int j = 1; j <= sheet.LastRowNum; j++)
                    {
                        IRow row = sheet.GetRow(j);
                        Person model = new Person
                        {
                            Name = row.GetCell(0).ToString(),
                            Age = Convert.ToInt32(row.GetCell(1).ToString())
                        };

                        personList.Add(model);
                    }
                }
            }

            return personList;
        }

        public static void InsertToDB(List<Person> personList)
        {
            string constr = "Data source=localhost;Initial catalog=DataModel;Integrated security=true";
            string sql = "insert into Person values(@name,@age)";

            foreach (var person in personList)
            {
                using (SqlConnection con = new SqlConnection(constr))
                {
                    using (SqlCommand command = new SqlCommand(sql, con))
                    {

                        con.Open();
                        SqlParameter[] pms = new SqlParameter[]
                        {
                            new SqlParameter("@name", SqlDbType.NVarChar, 50) {Value = person.Name},
                            new SqlParameter("@age", SqlDbType.Int) {Value = person.Age},
                        };
                        command.Parameters.AddRange(pms);
                        command.ExecuteNonQuery();
                    }
                }
            }
        }
    }

    class Person
    {
        public int AutoId { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
View Code

 

  五、其他的常见问题

  1.空值的问题

  在SqlServer数据库中,空值读取出来后是DBNull,这时可以先通过IsDBNull方法判断是不是DBNull,然后结合可空值类型与NOPI提供的CellType.BLANK结合来进行Excel写入(currentRow.CreateCell(i).SetCellType(CellType.BLANK);)。同理,读取Excel时,应该先判断是否是空值currentCell.CellType==CellType.BLANK,再根据情况向数据库中插入DBNull还是非空值。

  2.单元格数据格式样式问题

  有些类型的数据直接从Excel读取或者向Excel插入时需要做特殊的处理,如日期格式的数据,向Excel插入时,需要设置单元格样式

  {

    ICellStyle cellStyle = wk.CreateCellStyle();
              cellStyle.DataFormat=HSSFDataFormat.GetBuiltinFormat("mm/dd/yyyy hh:mm:ss");

    ICell cell = currentRow.CreateCell(5);
               cell.CellStyle = cellStyle;
               cell.SetValue((DateTime)lockDate);   

  }

  从Excel读取日期数据时,需要这样处理

  DateTime.FromOADate(currentCell.NumericCellValue);

  类似的细节还有很多,遇到的时候可以参考NOPI文档:http://npoi.codeplex.com/documentation

  

以上是关于使用NPOI操作Excel的主要内容,如果未能解决你的问题,请参考以下文章

.Net Core+NPOI快速导入导出Excel

NPOI操作Excel文件

NPOI操作excel

NPOI操作Excel 005:写入空Excel(Winform版)

NPOI操作Excel 004:写入空Excel(添加保存提示框)

使用NPOI操作Excel