zoukankan      html  css  js  c++  java
  • net core WebApi——使用NPOI导入导出操作

    前言

    时间过得好快,在之前升级到3.0之后,就感觉好久没再动过啥东西了,之前有问到Swagger的中文汉化,虽说我觉得这种操作的意义不是太大,也是多少鼓捣了下,其实个人感觉就是元素内容替换,既然可以执行js了那不就是网页上随便搞了,所以就没往下再折腾,但是现在需要用到Excel的操作了,那就不得不提起这个NPOI了。

    NPOI

    在之前.net framework的时候,工程需要用到Excel的导入导出,当然用这个NPOI是偶然,也就是找了下这个看着可以就用了,之后遇到的各种问题也都找资料解决,什么多行合并啊,打开2007版本错误啊之类的,但是不得不说,用着还挺好,所以既然net core需要了,那就看看呗,刚好也是支持的。

    Util我们来引入这个类库NPOI

    引入

    • 导入

    在使用之前,我们先缕一下获取Excel数据需要哪些准备操作。

    1. 获取文件(这个就不多说)
    2. 获取sheet信息(考虑有可能多sheet操作)
    3. 根据sheet获取对应文件信息(多少行,当然有些还有合并)
    4. 根据合并行来判断第一行是否为标题
    5. 判断哪一行是列名(用于对应数据)
    6. 遍历每一行并根据每一行的数据格式来获取(有可能是公式/日期/数字/普通文本等等)

    ok,大致上清楚了之后,我们就一步步来看吧,这里我创建一个ExcelUtil,来写第一个方法(这里只做说明展示吧)。

    	public class ExcelUtil
        {
            /// <summary>
            /// 读取Excel多Sheet数据
            /// </summary>
            /// <param name="filePath">文件路径</param>
            /// <param name="sheetName">Sheet名</param>
            /// <returns></returns>
            public static DataSet ReadExcelToDataSet(string filePath, string sheetName = null)
            {
                if (!File.Exists(filePath))
                {
                    LogUtil.Debug($"未找到文件{filePath}");
                    return null;
                }
                //获取文件信息
                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                IWorkbook workbook = WorkbookFactory.Create(fs);
                //获取sheet信息
                ISheet sheet = null;
                DataSet ds = new DataSet();
                if (!string.IsNullOrEmpty(sheetName))
                {
                    sheet = workbook.GetSheet(sheetName);
                    if (sheet == null)
                    {
                        LogUtil.Debug($"{filePath}未找到sheet:{sheetName}");
                        return null;
                    }
                    DataTable dt = ReadExcelFunc(workbook, sheet);
                    ds.Tables.Add(dt);
                }
                else
                {
                    //遍历获取所有数据
                    int sheetCount = workbook.NumberOfSheets;
                    for (int i = 0; i < sheetCount; i++) {
                        sheet = workbook.GetSheetAt(i);
                        if (sheet != null)
                        {
                            DataTable dt = ReadExcelFunc(workbook, sheet);
                            ds.Tables.Add(dt);
                        }
                    }
                }
                return ds;
            }
    
            /// <summary>
            /// 读取Excel信息
            /// </summary>
            /// <param name="workbook">工作区</param>
            /// <param name="sheet">sheet</param>
            /// <returns></returns>
            private static DataTable ReadExcelFunc(IWorkbook workbook, ISheet sheet)
            {
                DataTable dt = new DataTable();
                //获取列信息
                IRow cells = sheet.GetRow(sheet.FirstRowNum);
                int cellsCount = cells.PhysicalNumberOfCells;
                int emptyCount = 0;
                int cellIndex = sheet.FirstRowNum;
                List<string> listColumns = new List<string>();
                bool isFindColumn = false;
                while (!isFindColumn)
                {
                    emptyCount = 0;
                    listColumns.Clear();
                    for (int i = 0; i < cellsCount; i++)
                    {
                        if (string.IsNullOrEmpty(cells.GetCell(i).StringCellValue))
                        {
                            emptyCount++;
                        }
                        listColumns.Add(cells.GetCell(i).StringCellValue);
                    }
                    //这里根据逻辑需要,空列超过多少判断
                    if (emptyCount == 0)
                    {
                        isFindColumn = true;
                    }
                    cellIndex++;
                    cells = sheet.GetRow(cellIndex);
                }
    
                foreach (string columnName in listColumns)
                {
                    if (dt.Columns.Contains(columnName))
                    {
                        //如果允许有重复列名,自己做处理
                        continue;
                    }
                    dt.Columns.Add(columnName, typeof(string));
                }
                //开始获取数据
                int rowsCount = sheet.PhysicalNumberOfRows;
                cellIndex += 1;
                DataRow dr = null;
                for (int i = cellIndex; i < rowsCount; i++) {
                    cells = sheet.GetRow(i);
                    dr = dt.NewRow();
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        //这里可以判断数据类型
                        switch (cells.GetCell(j).CellType)
                        {
                            case CellType.String:
                                dr[j] = cells.GetCell(j).StringCellValue;
                                break;
                            case CellType.Numeric:
                                dr[j] = cells.GetCell(j).NumericCellValue.ToString();
                                break;
                            case CellType.Unknown:
                                dr[j] = cells.GetCell(j).StringCellValue;
                                break;
                        }
                    }
                    dt.Rows.Add(dr);
                }
                return dt;
            }
        }
    

    文件的导入操作就不再演示了,之前有文件上传的相关操作方法net core WebApi——文件分片上传与跨域请求处理

    导入的处理这里也只是大致演示下,具体需要的东西包括情况可能会比较复杂,但是终归数据还是那些,只是操作方法不同罢了(别说什么骚操作)。

    • 导出

    相对于导入,导出的流程就比较简单了。

    1. 获取数据信息(sql或文件)
    2. 组成数据集合(List或DataTable)
    3. 创建sheet
    4. 设置相关样式等等
    5. 遍历赋值row
    6. 导出文件流

    了解完,我们就继续来搞吧。

    		/// <summary>
            /// 导出Excel文件
            /// </summary>
            /// <typeparam name="T">数据类型</typeparam>
            /// <param name="entities">数据实体</param>
            /// <param name="dicColumns">列对应关系,如Name->姓名</param>
            /// <param name="title">标题</param>
            /// <returns></returns>
            public static byte[] ExportExcel<T>(List<T> entities,Dictionary<string,string> dicColumns, string title = null)
            {
                if (entities.Count <= 0)
                {
                    return null;
                }
                //HSSFWorkbook => xls
                //XSSFWorkbook => xlsx
                IWorkbook workbook = new XSSFWorkbook();
                ISheet sheet = workbook.CreateSheet("test");//名称自定义
                IRow cellsColumn = null;
                IRow cellsData = null;
                //获取实体属性名
                PropertyInfo[] properties = entities[0].GetType().GetProperties();
                int cellsIndex = 0;
                //标题
                if (!string.IsNullOrEmpty(title))
                {
                    ICellStyle style = workbook.CreateCellStyle();
                    //边框  
                    style.BorderBottom = BorderStyle.Dotted;
                    style.BorderLeft = BorderStyle.Hair;
                    style.BorderRight = BorderStyle.Hair;
                    style.BorderTop = BorderStyle.Dotted;
                    //水平对齐  
                    style.Alignment = HorizontalAlignment.Left;
    
                    //垂直对齐  
                    style.VerticalAlignment = VerticalAlignment.Center;
    
                    //设置字体
                    IFont font = workbook.CreateFont();
                    font.FontHeightInPoints = 10;
                    font.FontName = "微软雅黑";
                    style.SetFont(font);
    
                    IRow cellsTitle = sheet.CreateRow(0);
                    cellsTitle.CreateCell(0).SetCellValue(title);
                    cellsTitle.RowStyle = style;
                    //合并单元格
                    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 1, 0, dicColumns.Count - 1));
                    cellsIndex = 2;
                }
                //列名
                cellsColumn = sheet.CreateRow(cellsIndex);
                int index = 0;
                Dictionary<string, int> columns = new Dictionary<string, int>();
                foreach (var item in dicColumns)
                {
                    cellsColumn.CreateCell(index).SetCellValue(item.Value);
                    columns.Add(item.Value, index);
                    index++;
                }
                cellsIndex += 1;
                //数据
                foreach (var item in entities)
                {
                    cellsData = sheet.CreateRow(cellsIndex);
                    for (int i = 0; i < properties.Length; i++)
                    {
                        if (!dicColumns.ContainsKey(properties[i].Name)) continue;
                        //这里可以也根据数据类型做不同的赋值,也可以根据不同的格式参考上面的ICellStyle设置不同的样式
                        object[] entityValues = new object[properties.Length];
                        entityValues[i] = properties[i].GetValue(item);
                        //获取对应列下标
                        index = columns[dicColumns[properties[i].Name]];
                        cellsData.CreateCell(index).SetCellValue(entityValues[i].ToString());
                    }
                    cellsIndex++;
                }
    
                byte[] buffer = null;
                using (MemoryStream ms = new MemoryStream())
                {
                    workbook.Write(ms);
                    buffer = ms.GetBuffer();
                    ms.Close();
                }
    
                return buffer;
            }
    

    测试

    写完,免不了一通测试,这里不多说了,直接上图。

    导入这里前面也说了没做界面上传什么的,就是一个文件路径,直接执行,Excel原文件我也会同步上传到代码仓库。
    测试导入

    导出的话,这里也是用Swagger神器来测试。
    测试导出

    数据库数据如下图。
    测试

    测试导出

    带标题导出。
    测试导出

    小结

    最近真的是有点儿忙,一直在鼓捣opengl这类图形化的东西,各种矩阵转换模型转换,要么是用c++,qt写opengl,要么是用threejs搞opengl,唉,整的最近也只能是晚上回去摸索会儿net core,工作总是不那么尽如人意,但是身为程序猿的我们,不都是不断的摸索前进么?我们可以不会,但那不是我们不整的借口。

  • 相关阅读:
    A working example of bad SQL statement causes too much CPU usage
    Notes on <<Refactoring Databases Evolutionary Database Design>>
    DBMS_SQL & ORA01000: Too many open cursors
    TTS, not used for schema exp/imp
    Notes on <High Performance MySQL> Ch6: Optimizing Server Settings
    Notes on <High Performance MySQL> Ch3: Schema Optimization and Indexing
    A bug of "sql*loader"?
    11.2.0.2 improves the support for MERGE statement
    Use "OR" in SQL with caution
    关于NORFLASH和NANDfLASH的区别。——Arvin
  • 原文地址:https://www.cnblogs.com/AprilBlank/p/11698261.html
Copyright © 2011-2022 走看看