使用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;
        }  
      
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章