C# NOPI常用方法(记录老项目的方法)

最近在维护公司的十年老项目。写了一些nopi的方法,记录一下。

        /// <summary>
        /// DataTable转成Excel表格
        /// </summary>
        /// <returns></returns>
        public static byte[] DataTableToExcel(DataTable dt)
        {
            using (HSSFWorkbook hssfworkbook = new HSSFWorkbook())//建立Excel 2003对象
            using (HSSFSheet sheet = (HSSFSheet)hssfworkbook.CreateSheet("sheet1"))//新建一个名称为sheet1的工作簿
            using (MemoryStream stream = new MemoryStream()) //二进制流中介
            {
                DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();//配置文件属性
                dsi.Company = string.Empty;
                dsi.Category = string.Empty;//类别
                dsi.Manager = string.Empty;//管理者
                hssfworkbook.DocumentSummaryInformation = dsi;
                SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
                si.Subject = string.Empty;//主题
                si.Title = string.Empty;//标题
                si.ApplicationName = string.Empty;//不知道是啥
                si.Author = string.Empty;//作者
                si.LastAuthor = string.Empty;//上一次保存者
                si.Comments = string.Empty;//备注
                si.CreateDateTime = DateTime.Now;
                hssfworkbook.SummaryInformation = si;

                //Func<HSSFWorkbook, string, short, HSSFCellStyle> setstyle =
                //    (hssfwb, fontname, fontsize)
                //     =>
                //     {
                //         HSSFFont font = (HSSFFont)hssfwb.CreateFont();
                //         HSSFCellStyle style = (HSSFCellStyle)hssfwb.CreateCellStyle();
                //         style.SetFont(font);
                //         font.FontName = fontname;
                //         font.FontHeightInPoints = fontsize;
                //         return style;
                //     };

                ////表格设置
                //sheet.SetColumnWidth(1, 30 * 256);//第二列较宽 
                //sheet.DefaultColumnWidth = 13;
                //HSSFCellStyle style0 = setstyle(hssfworkbook, "微软雅黑", 14);
                //HSSFCellStyle style1 = setstyle(hssfworkbook, "微软雅黑", 12);

                //设置列名
                HSSFRow row = (HSSFRow)sheet.CreateRow(0);
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    Cell cell = row.CreateCell(i);
                    cell.SetCellValue(dt.Columns[i].ColumnName);
                    //cell.CellStyle = style0;
                }
                //单元格赋值
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    Row row1 = sheet.CreateRow(i + 1);
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        Cell cell = row1.CreateCell(j);
                        var value = dt.Rows[i][j];
                        if (value != null && value != DBNull.Value)
                        {
                            var valueType = value.GetType();

                            if (valueType == typeof(double) || valueType == typeof(decimal) || valueType == typeof(float) ||
                                valueType == typeof(double?) || valueType == typeof(decimal?) || valueType == typeof(float?) ||
                                valueType == typeof(byte) || valueType == typeof(int) || valueType == typeof(long) ||
                                valueType == typeof(byte?) || valueType == typeof(int?) || valueType == typeof(long?)
                                )
                            {
                                cell.SetCellValue(Convert.ToDouble(value));
                            }
                            else
                            {
                                cell.SetCellValue(value.ToString());
                            }
                        }
                        else
                        {
                            cell.SetCellValue(string.Empty);
                        }
                        //cell.CellStyle = style1;
                    }
                }
                hssfworkbook.Write(stream);
                return stream.ToArray();
            }
        }

//使用
DataTable dt = GetDataTable();
dt.TableName = "导出的Excel";
DataTableToExcel(dt);
        /// <summary>
        /// 获取带数据的模版表格
        /// </summary>
        /// <param name="columns">Key为数据库的列名,Value为表格中显示的列名称。</param>
        /// <param name="templetePath">模版文件的路径</param>
        /// <param name="data">数据库中的数据</param>
        /// <returns></returns>
        public static byte[] GetDataTempleteExcel(Dictionary<string, string> columns, string templetePath, DataTable data)
        {
            using (FileStream fs = new FileStream(templetePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            using (HSSFWorkbook workbook = new HSSFWorkbook(fs))
            using (HSSFSheet sheet1 = workbook.GetSheetAt(0) as HSSFSheet)
            using (MemoryStream stream = new MemoryStream())
            {
                HSSFRow headerRow = sheet1.GetRow(0) as HSSFRow;//获取sheet的首行
                int cellCount = headerRow.LastCellNum;  //一行最后一个方格的编号 即总的列数
                int cellRowsCount = sheet1.LastRowNum + 1;//这个好像是获取的下标,所以加一。

                if (cellCount != columns.Count)
                {
                    throw new ArgumentException(nameof(columns));
                }
                if (cellRowsCount < 1)
                {
                    throw new ArgumentNullException(nameof(cellRowsCount));
                }

                //赋值前清除下数据
                for (int i = 1; i < cellRowsCount; i++) if (sheet1.GetRow(i) == null) continue; else sheet1.RemoveRow(sheet1.GetRow(i));

                DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();//配置文件属性
                dsi.Company = string.Empty;
                dsi.Category = string.Empty;//类别
                dsi.Manager = string.Empty;//管理者
                workbook.DocumentSummaryInformation = dsi;
                SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
                si.Subject = string.Empty;//主题
                si.Title = string.Empty;//标题
                si.ApplicationName = string.Empty;//不知道是啥
                si.Author = string.Empty;//作者
                si.LastAuthor = string.Empty;//上一次保存者
                si.Comments = string.Empty;//备注
                si.CreateDateTime = DateTime.Now;
                workbook.SummaryInformation = si;

                DataRow[] dataRows = data.AsEnumerable().ToArray();
                string[] columnNames = columns.Keys.ToArray();

                //数据库中的列名,按照Excel中的列顺序排列。
                List<string> dbColumnNames = new List<string>();
                var columnRow = sheet1.GetRow(0);
                for (int i = 0; i < cellCount; i++)
                {
                    var excelColumnName = columnRow.GetCell(i).ToString().Trim();
                    foreach (var colKey in columnNames)
                    {
                        if (string.Equals(columns[colKey], excelColumnName, StringComparison.OrdinalIgnoreCase))
                        {
                            dbColumnNames.Add(colKey);
                            break;
                        }
                    }
                }

                //转成数组使用,因为感觉这样后面使用快一点。
                string[] dbColumnNamesArray = dbColumnNames.ToArray();

                if (dbColumnNamesArray.Length != cellCount)
                {
                    throw new ArgumentException(nameof(dbColumnNamesArray));
                }

                //单元格赋值
                for (int i = 0, c = dataRows.Length; i < c; i++)
                {
                    Row row1 = sheet1.CreateRow(i + 1);
                    for (int j = 0; j < cellCount; j++)
                    {
                        Cell cell = row1.CreateCell(j);
                        var value = dataRows[i][dbColumnNamesArray[j]];
                        if (value != null && value != DBNull.Value)
                        {
                            cell.SetCellValue(value.ToString());
                        }
                        else
                        {
                            cell.SetCellValue(string.Empty);
                        }
                    }
                }

                workbook.Write(stream);
                return stream.ToArray();
            }
        }

//使用
var columns = new Dictionary<string, string>()
{
  { "Name","名称" },
  { "Age","年龄" },
};
DataTable dt = GetDataTable();
dt.TableName = "导出的Excel";
DataTableToExcel(columns,Server.MapPath("~/template/test.xls"),dt);
        /// <summary>
        /// 获取excel单元格中的值
        /// </summary>
        /// <param name="cellObj"></param>
        /// <returns></returns>
        public static string GetExcelCellValue(Cell cellObj, NPOI.SS.UserModel.Workbook workbook)
        {
            if (cellObj == null) return string.Empty;

            string cellValue = null;

            switch (cellObj.CellType)
            {
                case CellType.Unknown:
                    break;
                case CellType.NUMERIC:
                    //NPOI中数字和日期都是NUMERIC类型的,这里对其进行判断是否是日期类型
                    if (DateUtil.IsCellDateFormatted(cellObj))//日期类型
                    {
                        var date = cellObj.DateCellValue;
                        if (date != default(DateTime) && date != DateTime.MinValue)
                        {
                            cellValue = date.ToString("yyyy/MM/dd HH:mm:ss");
                        }
                    }
                    else//其他数字类型
                    {
                        cellValue = cellObj.NumericCellValue.ToString();
                    }
                    break;
                case CellType.STRING:
                    cellValue = cellObj.StringCellValue;
                    break;
                case CellType.FORMULA:
                    var eva = new NPOI.HSSF.UserModel.HSSFFormulaEvaluator(workbook);
                    cellValue = eva.Evaluate(cellObj).StringValue;
                    break;
                case CellType.BLANK:
                    break;
                case CellType.BOOLEAN:
                    cellValue = cellObj.BooleanCellValue.ToString();
                    break;
                case CellType.ERROR:
                    cellValue = cellObj.ErrorCellValue.ToString();
                    break;
                default:
                    break;
            }

            cellValue = string.IsNullOrWhiteSpace(cellValue) ? string.Empty : cellValue.Trim();

            return cellValue;
        }

/*下面的代码虽然是我写的,但是我不是很清楚啥作用了。而且是和业务以及asp的控件交织在一起的,所以这个也就记录下,不需要看懂。*/

        /// <summary>
        /// 上传Excel并且返回Excel中的数据
        /// </summary>
        /// <param name="columns">表列名和Excel中的列名字典</param>
        /// <param name="fuInvoiceFile">上传文件的控件</param>
        /// <returns>1:是否上传成功;2:上传成功后的数据;3:上传失败的错误消息;4:当前Excel的对象;5.文件上传后的地址</returns>
        protected Tuple<bool, DataTable, string, Workbook, string> GetExcelDataTable(Dictionary<string, string> columns, FileUpload fuInvoiceFile)
        {
            #region 文件校验、上传到服务器

            string fileName = fuInvoiceFile.ShortFileName.Replace(":", "_").Replace(" ", "_").Replace("\", "_").Replace("/", "_");
            if (fileName.LastIndexOf('.') <= 0)
            {
                return new Tuple<bool, DataTable, string, Workbook, string>(false, null, "- 文件错误!", null, null);
            }
            string fileExt = fileName.Substring(fileName.LastIndexOf("."));
            // 文件验证
            if (fileExt != ".xls" && fileExt != ".xlsx")
            {
                return new Tuple<bool, DataTable, string, Workbook, string>(false, null, "- 只能选择Excel文件导入!", null, null);
            }
            string onlyFileName = fileName.Substring(0, fileName.LastIndexOf(".") + 1);
            string dir = $@"{Server.MapPath(@"upfile")}{DateTime.Now:yyyy-MM-dd}";
            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);  // 创建日期目录
            string filePath = $"{dir}{onlyFileName}{Guid.NewGuid().ToString().Replace("-", string.Empty)}{fileExt}"; // 获得文件保存在服务器上的路径

            // 保存文件到服务器
            fuInvoiceFile.PostedFile.SaveAs(filePath);

            #endregion

            #region 实例化一个Excel

            FileStream fs = new FileStream(filePath, FileMode.Open);
            NPOI.SS.UserModel.Workbook workbook = new NPOI.HSSF.UserModel.HSSFWorkbook(fs);
            fs.Dispose();
            NPOI.SS.UserModel.Sheet sheet = workbook.GetSheetAt(0);
            if (sheet == null)
            {
                sheet = workbook.CreateSheet("Sheet1");
            }

            #endregion

            #region 文件校验

            if (sheet.PhysicalNumberOfRows < 2)
            {
                return new Tuple<bool, DataTable, string, Workbook, string>(false, null, "- 未获取到数据,请检查数据文件!", null, null);
            }

            var headerRow = sheet.GetRow(0) as NPOI.HSSF.UserModel.HSSFRow;//获取sheet的首行
            int cellCount = headerRow.LastCellNum;  //一行最后一个方格的编号 即总的列数
            //int cellRowsCount = sheet.LastRowNum + 1;//这个好像是获取的下标,所以加一。

            if (cellCount != columns.Count)
            {
                return new Tuple<bool, DataTable, string, Workbook, string>(false, null, "- 列数不正确,请检查Excel文件!", null, null);
            }


            DataTable dt = new DataTable();
            var columnsKeys = columns.Keys.ToArray();
            for (int j = 0, clos = columnsKeys.Length; j < clos; j++)
            {
                var headerText = headerRow.GetCell(j).ToString();

                bool isNotExits = true;

                foreach (var headerKey in columnsKeys)
                {
                    var columnName = columns[headerKey];
                    if (columnName == headerText)
                    {
                        dt.Columns.Add(headerKey, typeof(string));
                        isNotExits = false;
                        break;
                    }
                }

                if (isNotExits)
                {
                    return new Tuple<bool, DataTable, string, Workbook, string>(false, null, $"- 列名称[{headerText}]无法匹配,请使用系统提供的Excel模版导入!", null, null);
                }
            }

            #endregion

            #region 读取数据

            for (int i = 1, rows = sheet.PhysicalNumberOfRows; i < rows; i++)
            {
                var dtRow = dt.NewRow();
                for (int j = 0, clos = columnsKeys.Length; j < clos; j++)
                {
                    Row excelRow = sheet.GetRow(i);
                    if (excelRow == null) excelRow = sheet.CreateRow(i);
                    Cell cellObj = excelRow.GetCell(j);
                    if (cellObj == null) cellObj = excelRow.CreateCell(j);

                    dtRow[j] = DataTableRenderToExcel.GetExcelCellValue(cellObj, workbook);
                }
                dt.Rows.Add(dtRow);
            }


            #endregion

            #region 数据处理

            /// <summary>
            /// 删除DataTable下方的空数据行
            /// </summary>
            /// <param name="dt">要删除下方空数据行的数据列表</param>
            /// <param name="startIndex">有效列开始下标</param>
            /// <param name="endIndex">有效列结束下标</param>
            void DeleteDataTableBelowNullData(DataTable dtd, int startIndex, int endIndex)
            {
                if (dtd == null) return;

                int colLength = endIndex - startIndex + 1;

                for (int i = dtd.Rows.Count - 1; i >= 0; i--)
                {
                    var row = dtd.Rows[i].ItemArray;
                    int j = 0;
                    for (int y = startIndex; y <= endIndex; y++)
                    {
                        if (string.IsNullOrWhiteSpace(row?[y]?.ToString()))
                        {
                            j++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (j == colLength)
                    {
                        dtd.Rows.RemoveAt(i);
                    }
                    else
                    {
                        break;
                    }
                }
            }

            DeleteDataTableBelowNullData(dt, 1, dt.Columns.Count - 1);

            #endregion

            return new Tuple<bool, DataTable, string, Workbook, string>(true, dt, null, workbook, filePath);
        }

        /// <summary>
        /// 执行Excel导入错误校验
        /// </summary>
        /// <param name="workbook">需要写入的Excel对象</param>
        /// <param name="messages">错误消息集合</param>
        /// <param name="filePath">Excel文件地址</param>
        /// <returns></returns>
        protected Tuple<bool, string> ExeExcelErrorMessage(Workbook workbook, List<string> messages, string filePath)
        {
            var sheet = workbook.GetSheetAt(0);

            Row excelRowHead = sheet.GetRow(0);

            int errorColIndex = excelRowHead.LastCellNum + 1;

            if (excelRowHead == null) excelRowHead = sheet.CreateRow(0);
            Cell excelCellErrorTipHead = excelRowHead.GetCell(errorColIndex);
            if (excelCellErrorTipHead == null) excelCellErrorTipHead = excelRowHead.CreateCell(errorColIndex);
            excelCellErrorTipHead.SetCellValue("导入提示");

            bool hasError = false;

            for (int i = 0, count = messages.Count; i < count; i++)
            {
                string errorMessage = messages[i];
                Row excelRow = sheet.GetRow(i + 1);
                if (errorMessage.Length > 0)
                {
                    Cell cell = excelRow.GetCell(errorColIndex);
                    if (cell == null) cell = excelRow.CreateCell(errorColIndex);
                    cell.SetCellValue(errorMessage);
                    hasError = true;
                }
            }

            string navigateUrl = null;

            if (hasError)
            {
                navigateUrl = string.Format("~/upfile/{0}/{1}", DateTime.Now.ToString("yyyy-MM-dd"), filePath.Substring(filePath.LastIndexOf('\') + 1));

                var fs = new FileStream(Server.MapPath(navigateUrl), FileMode.OpenOrCreate, FileAccess.ReadWrite);
                workbook.Write(fs);
                fs.Dispose();

            }
            else
            {
                if (File.Exists(filePath)) File.Delete(filePath);
            }
            workbook.Dispose();

            return new Tuple<bool, string>(hasError, navigateUrl);
        }
原文地址:https://www.cnblogs.com/cluyun/p/14752228.html