使用NPOI完全脱离excel的导出三,批量数据导出性能优化

之前写过一篇使用使用NPOI完全脱离excel的导出二,批量数据导出性能优化,但在实际使用中发现,导出五万条数据,需要近三十秒,这还不包括读取数据的时间。于是看看还能不能优化。

 通过测试发现速度慢主要体现在一下两个方面:

1是把IWorkbook写入内存流,看着似乎没办法修改。

 internal static MemoryStream Export(IWorkbook workbook,int count)
    {
        try
        {    
            MemoryStream ms = new MemoryStream(count*20);
            workbook.Write(ms);
            return ms;
        }
        catch (Exception ex)
        {
            new AppException("导出文件错误MemoryStream", ex);
            return null;
        }
    }

2循环输出Excel,在循环中使用了反射来提取数据,于是把反射修改如下:

 public static Func<T, object> EmitGetter<T>(string propertyName)
    {
        var type = typeof(T);
        var dynamicMethod = new DynamicMethod("get_" + propertyName, typeof(object), new[] { type }, type);
        var iLGenerator = dynamicMethod.GetILGenerator();
        iLGenerator.Emit(OpCodes.Ldarg_0);
        var property = type.GetProperty(propertyName);
        iLGenerator.Emit(OpCodes.Callvirt, property.GetGetMethod(true));
        if (property.PropertyType.IsValueType)
        {
            // 如果是值类型,装箱
            iLGenerator.Emit(OpCodes.Box, property.PropertyType);
        }
        else
        {
            // 如果是引用类型,转换
            iLGenerator.Emit(OpCodes.Castclass, property.PropertyType);
        }
        iLGenerator.Emit(OpCodes.Ret);
        return dynamicMethod.CreateDelegate(typeof(Func<T, object>)) as Func<T, object>;
    }
    public static object EmitGetterValue<T>(T model, string propertyName)
    {
        var getMethod = EmitGetter<T>(propertyName);
        return getMethod(model);
    }

3在设置Excel值是使用了typeof,于是也修改如下

 

在生成字典时,生成字段和类型关系的字典

 Dictionary<string, FieldType> FieldNamesPropertyInfoDic = new Dictionary<string, FieldType>();
            Dictionary<string, Func<Titem, object>> FieldNamesMethodInfoDic = new Dictionary<string, Func<Titem, object>>();         
            if (list.Count > 0)
            {
                foreach (KeyValuePair<string, string> column in FieldNames)
                {
                    var getterMethod = EmitGetter<Titem>(column.Key);
                    string key = column.Key;
                    PropertyInfo pinfo = typeof(Titem).GetProperty(key);
                    if (pinfo != null)
                    {
                        if (!FieldNamesPropertyInfoDic.ContainsKey(key))
                        {
                            Type modePropertyType = pinfo.PropertyType;
                            FieldType fieldType= ExportTreeData<Titem>.GetFieldType(modePropertyType);
                            FieldNamesPropertyInfoDic.Add(key, fieldType);
                            FieldNamesMethodInfoDic.Add(key, getterMethod);
                        }
                    }
                    else
                    {
                        new AppException("导出文件错误未找到关联的属性" + column.Key);
                        throw new Exception("未找到关联的属性" + column.Key + "");
                    }
                }
            }
            else
            {
                return sheet;
            }

设置单元格的值

这样修改之后性能确实有所提高,但只能提高百分之二十左右,没有质的飞跃,于是有寻找其他的方法。

想不到竟然找到了。

竟然也是一句代码,修改IWorkbook的类型

 private IWorkbook Getworkbook()
    {
        if (workbook == null)
        {
            //  workbook = new HSSFWorkbook(); 2003版本
            XSSFWorkbook workbooktmp = new XSSFWorkbook();//2007版本
            workbook = new SXSSFWorkbook(workbooktmp,500);
        }
        return workbook;
    }

XSSFWorkbook修改为SXSSFWorkbook二十秒直接变成了六秒!!!

唯一的问题是这种类型没有了,日期类型,只能把日期类型做为字符串处理。

相关代码:

枚举定义:

/*  
 *  根据单元的SetCellValue的方法设置四种枚举值
        void SetCellValue(bool value);       
        void SetCellValue(string value);       
        void SetCellValue(IRichTextString value);       
        void SetCellValue(DateTime value);      
        void SetCellValue(double value);
     */
public enum FieldType
{
    //字符
    Sstring,
    //时间
    SDateTime, 
    //数值
    Sdouble, 
    //bool值
    Sbool
}

根据反射获取枚举

 public static FieldType GetFieldType(Type modePropertyType)
    {       
        if (modePropertyType == typeof(string))
        {          
            return FieldType.Sstring;
        }
        else if (modePropertyType == typeof(DateTime))
        {         
            return FieldType.SDateTime;
        }
        else if (modePropertyType == typeof(DateTime?))
        {
            return FieldType.SDateTime;
        }
        else if (modePropertyType == typeof(bool))
        {
            return FieldType.Sbool;
        }
        else if (modePropertyType == typeof(bool?))
        {
            return FieldType.Sbool;
        }
        else if (modePropertyType == typeof(float?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(decimal?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(double?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(int?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(int))
        {
            return FieldType.Sdouble; ;
        }
        else if (modePropertyType == typeof(float))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(double))
        {
            return FieldType.Sdouble;
        }

        else if (modePropertyType == typeof(decimal))
        {
            return FieldType.Sdouble;
        }

        else if (modePropertyType == typeof(sbyte))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(sbyte?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(byte))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(byte?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(short))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(short?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(ushort))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(ushort?))
        {
            return FieldType.Sdouble;
        }

        else if (modePropertyType == typeof(uint))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(uint?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(long))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(long?))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(ulong))
        {
            return FieldType.Sdouble;
        }
        else if (modePropertyType == typeof(ulong?))
        {
            return FieldType.Sdouble;
        }             
        return FieldType.Sstring;
    }

设置单元格的值

 public static void SetCellValue(FieldType modePropertyType, ICell newCell, string drValue)
    {
        if (string.IsNullOrEmpty(drValue))
        {
            return;
        }
        switch(modePropertyType)
        {
            case FieldType.Sstring:
                newCell.SetCellValue(drValue);
                break;
            case FieldType.SDateTime:
                //SXSSFWorkbook没有实现时间的方法
                newCell.SetCellValue(Convert.ToDateTime(drValue).ToString("yyyy-MM-dd"));
                break;
            case FieldType.Sdouble:
                newCell.SetCellValue(Convert.ToDouble(drValue));
                break;
            case FieldType.Sbool:
                newCell.SetCellValue(Convert.ToBoolean(drValue));
                break;          
            default:
                newCell.SetCellValue(drValue);
                break;
        }  
      
    }

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页