C# NPOI读写Excel

来源:互联网 发布:网络任务兼职 编辑:程序博客网 时间:2024/04/29 09:08

  上次写了一个java POI读写excel的工具类,JAVA中读写excel有同样的方法,即是NPOI,NPOI的DLL下载地址NPOI下载地址,这两个应该是一个东西,用法相同,这个封装的方法其实是和JAVA的那个封装了同样的功能,但也稍微有点不同,这个封装了应该比java那个稍微好用一点,其他废话不说了,直接上代码:

1、读取Excel

  <span style="font-size:14px;">      /// <summary>        /// 读取excel        /// </summary>        /// <typeparam name="T">实体类</typeparam>        /// <param name="path">文件路径</param>        /// <param name="stream">文件流</param>        /// <param name="skipTitls">是否跳过首行</param>        /// <returns>返回集合</returns>        public static List<T> ReadExcelFile<T>(string path, Stream stream, bool skipTitls = true)        {            List<T> listT = new List<T>();            //if (stream == null && string.IsNullOrEmpty(path))            //{            //    return listT;            //}            if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path)) //判断文件存在            {                FileStream fStream = new FileStream(path, FileMode.Open, FileAccess.Read);                stream = fStream;            }            if (stream == null)            {                return listT;            }            Type ttype = typeof(T);            PropertyInfo[] pinfo = ttype.GetProperties();//获取实体属性数组            HSSFWorkbook wk = new HSSFWorkbook(stream);            for (int i = 0; i < wk.NumberOfSheets; i++)            {                ISheet sheet = wk.GetSheetAt(i); //读取sheet                int j = 0;                if (skipTitls)  //跳过首行                {                    j = 1;                }                for (int lastRow = sheet.LastRowNum; j <= lastRow; j++)                {                    IRow row = sheet.GetRow(j);                    if (row == null)                    {                        continue;                    }                    T tobj = (T)Activator.CreateInstance(ttype); //新建对象                    for (int k = 0, rowlastnum = row.LastCellNum; k <= rowlastnum; k++)                    {                        ICell cell = row.GetCell(k);                        if (cell == null || cell.ToString().Trim() == "")                        {                            //pinfo[k].SetValue(tobj, "");                            continue;                        }                        try                        {                            var cellvalue = Convert.ChangeType(cell.ToString().Trim(), pinfo[k].PropertyType);//类型强转                            pinfo[k].SetValue(tobj, cellvalue);//属性赋值                        }                        catch (Exception e)                        {                            //string cellindex = "sheet=" + i + "++row=" + j + "+cell=+" + k;                            //throw e;                        }                    }                    listT.Add(tobj);                }            }            return listT;        }</span>

同样用的反射来进行读取,里面代码就不介绍了,就只强调一点,这里读取分为路径读取和流读取,当路径为空的时候,默认以流参数为准,如果流为空则返回集合,如果路径不为空,且路径文件存在,则以路径参数为准,JAVA的那个介绍的已经很清楚了,接下来excel的导出方法:

2、Excel导出

  <span style="font-size:14px;">    /// <summary>        /// 导出excel        /// </summary>        /// <typeparam name="T">实体类型</typeparam>        /// <param name="list">要导出的集合</param>        /// <param name="excelname">文件及sheet名</param>        /// <param name="isUsetitles">是否用标题,true用,false 不用</param>        /// <param name="titles">标题</param>        /// <returns>返回导出状态</returns>        public static bool ExportExcel<T>(List<T> list, String excelname, bool isUsetitles = false, params String[] titles)        {            bool resultBool = false;            if (list == null || list.Count <= 0)            {                return resultBool; //空集合返回false            }            if (string.IsNullOrEmpty(excelname))            {                excelname = DateTime.Now.ToString("yyyyMMddhhmmss");//无文件名默认取当前的时间            }            HSSFWorkbook hbook = Hssbook<T>(list, excelname, isUsetitles, titles);//要导出的sheet            HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";            HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.xls", excelname));//设置导出头信息            MemoryStream mStream = null;            try            {                mStream = new MemoryStream();                hbook.Write(mStream); //写入内存流                HttpContext.Current.Response.BinaryWrite(mStream.ToArray());                hbook = null;                mStream.Close();                mStream.Dispose(); //释放关闭流信息                resultBool = true;            }            catch (Exception e)            {                if (mStream != null)                {                    hbook = null;                    mStream.Close();                    mStream.Dispose();                }            }            //HttpContext.Current.Response.End();            return resultBool;        }</span>

       同样的最后的可变参数用来设置要导出内容每列的标头,但是不同的是加了一个bool的参数isUseTitles,默认为false,不使用自定义的每列的标头,即你集合是什么内容,结果就导出什么内容,不会有每列的标题信息,当这个参数为ture的时候是使用标题列,因此,每列第一行会设置你自定义的标题。

       private static HSSFWorkbook Hssbook<T>(List<T> list, String excelname, bool isUsetitles = false, params String[] titles)        {            Type ttype = typeof(T);            PropertyInfo[] pinfos = ttype.GetProperties();            HSSFWorkbook workbook = new HSSFWorkbook();            ISheet sheet = workbook.CreateSheet(excelname);//新建sheet                   ICellStyle hstyle = workbook.CreateCellStyle();            hstyle.VerticalAlignment = VerticalAlignment.Center; //水平居中            int count = titles.Length;            int celllen = pinfos.Length;            //IRow row = sheet.CreateRow(0);            if (isUsetitles) //判断是否使用自定义头信息            {                IRow row = sheet.CreateRow(0);                for (int i = 0; i < count; i++)                {                    ICell cell = row.CreateCell(i);                    cell.SetCellValue(titles[i]);                    cell.CellStyle = hstyle;                    sheet.AutoSizeColumn(i);                }                celllen = count;            }            else            {                //或者可以在不使用头的时候用字段的属性值,但这样感觉没必要                //IRow row = sheet.CreateRow(0);                //for (int i = 0; i < celllen; i++)                //{                //    ICell cell = row.CreateCell(i);                //    cell.SetCellValue(pinfos[i].Name);                //    cell.CellStyle = hstyle;                //    sheet.AutoSizeColumn(i);                //}            }            // int celllen = pinfos.Length > count&&isUsetitles? count : pinfos.Length;            for (int i = 0, rowlen = list.Count; i < rowlen; i++)            {                int forindex = i;                if (isUsetitles)                {                    forindex++;                }                // IRow rowitem = sheet.CreateRow(i + 1);                IRow rowitem = sheet.CreateRow(forindex);                for (int j = 0; j < celllen; j++)                {                    //String fileString = "";                    ICell itemcell = rowitem.CreateCell(j);                    object obvalue = pinfos[j].GetValue(list[i]);//取值                    if (obvalue == null)                    {                        continue;                    }                    //if (obvalue != null)                    //{                    String fileString = obvalue.ToString();                    // }                    itemcell.SetCellValue(fileString);                    sheet.AutoSizeColumn(j);                }            }            return workbook;        }

   有一点要注意,当你把isUseTitles设置为true的时候,要导出的列的数量就不会根据你list集合对象字段的数量来确定,而是根据你设置的标头的数量来确定,你有两个标头,他就会导出两列,四个标头导出四列,如果你在可变参数中没有自定义设置标头,那么他一列都不会导出,直接是空画布。

导出的用法都一样,就直接把那个复制过来了,如下:

<input type="button" onclick="ExportExcel()" value="导出EXCEL" />  <script type="text/javascript">  function ExportExcel(){          location.href="ExportExcel";//请求地址  }   </script> 


 好了,写到这里吧,要睡觉了,有啥不明白的可以看我写的那个java POI读写Excel的文章,那个写的详细一点,用法基本相同。结束了,有啥不对或者需要优化的地方请大家批评指出,我会尽快改正。谢谢!!




1 0
原创粉丝点击