【问题标题】:Optimize C# method that compares and creates a differences Excel file优化比较和创建差异 Excel 文件的 C# 方法
【发布时间】:2011-02-28 22:36:34
【问题描述】:

这个问题和我之前的问题Link有关 下面的方法完全符合我的需要,但我需要让它运行得更快。 有人有什么建议吗?谢谢。

        public bool createReport_NewMinusBase(string currentWorkingDirectory, string Book1, string Book2, double tolerance)
        {
            tolerance = 0.0001;
            myExcel.Application excelApp = new myExcel.Application();  // Creates a new Excel Application
            excelApp.Visible = false;  // Makes Excel visible to the user.
            excelApp.Application.DisplayAlerts = false;

            //useful for COM object interaction
            object missing = System.Reflection.Missing.Value;

            //Return value
            bool wereDifferences = false;

            //Comparison objects
            object objNew = null;
            object objBase = null;


            //source: http://www.codeproject.com/KB/office/csharp_excel.aspx
            //xlApp.Workbooks.Open(reportFolder + reportName, 0, false, 5, "", "", false, myExcel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);

            //Open BASE FILE
            myExcel.Workbook excelWorkbook1 = excelApp.Workbooks.Open(@currentWorkingDirectory + Book1, 0,
                                              missing, missing, missing, missing, missing, missing, 
                                              missing,missing, missing, missing, missing, missing, missing);
            //OPEN NEW FILE
            myExcel.Workbook excelWorkbook2 = excelApp.Workbooks.Open(@currentWorkingDirectory + Book2, 0, 
                                              missing, missing, missing, missing, missing, missing, 
                                              missing, missing, missing, missing, missing, missing, missing);

            myExcel.Workbook excelWorkbook3 = excelApp.Application.Workbooks.Add(myExcel.XlWBATemplate.xlWBATWorksheet);

            myExcel.Worksheet wsBase;
            myExcel.Worksheet wsDiff;
            myExcel.Worksheet wsNew;


            try
            {
                wsBase = (myExcel.Worksheet)excelApp.Workbooks[Book1].Sheets["Sheet1"];
                wsNew = (myExcel.Worksheet)excelApp.Workbooks[Book2].Sheets["Sheet1"];
                wsDiff = (myExcel.Worksheet)excelWorkbook3.Worksheets.get_Item(1);
            }
            catch
            {
                throw new Exception("Excel file does not contain properly formatted worksheets");

            }


            //Copy Sheet from Excel Book "NEW" to "NEW(-)BASE"
            myExcel.Worksheet source_sheet;
            source_sheet = (myExcel.Worksheet)excelApp.Workbooks[Book2].Sheets["Sheet1"];
            source_sheet.UsedRange.Copy();
            wsDiff.Paste();




            //Determine working area
            int row = 0;
            int col = 0;
            int maxR = 0;
            int maxC = 0;

            int lr1 = 0;
            int lr2 = 0;
            int lc1 = 0;
            int lc2 = 0;
            {
                lr1 = wsNew.UsedRange.Rows.Count;
                lc1 = wsNew.UsedRange.Columns.Count;
            }

            {
                lr2 = wsBase.UsedRange.Rows.Count;
                lc2 = wsBase.UsedRange.Columns.Count;
            }

            maxR = lr1;
            maxC = lc1;

            if (maxR < lr2) maxR = lr2;
            if (maxC < lc2) maxC = lc2;

            //===================================================
            //Compare Cells
            //===================================================

            for (row = 1; row <= maxR; row++)
            {
                for (col = 1; col <= maxC; col++)
                {
                    //Get cell values
                    objNew = ((myExcel.Range)wsNew.Cells[row, col]).Value2;
                    objBase = ((myExcel.Range)wsBase.Cells[row, col]).Value2;


                    //If they are not equivilante
                    if (!equiv(objNew, objBase, tolerance))
                    {
                        wereDifferences = true;

                        //Mark differing cells
                        ((myExcel.Range)wsNew.Cells[row, col]).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
                        ((myExcel.Range)wsBase.Cells[row, col]).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);

                        if ((objNew == null))
                        {                            
                            ((myExcel.Range)wsDiff.Cells[row, col]).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
                        }
                        else if (objNew.GetType().ToString() == "System.String")
                        {
                            ((myExcel.Range)wsDiff.Cells[row, col]).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
                        }
                        else
                        {
                            ((myExcel.Range)wsDiff.Cells[row, col]).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Yellow);
                            ((myExcel.Range)wsDiff.Cells[row, col]).Value2 = ((myExcel.Range)wsNew.Cells[row, col]).Value2 - ((myExcel.Range)wsBase.Cells[row, col]).Value2;
                        }
                    }
                    else //They are equivalent
                    {                        
                        if ((objNew == null))
                        {
                        }
                        else if (objNew.GetType().ToString() == "System.String")
                        {
                        }
                        else
                        {                            
                            ((myExcel.Range)wsDiff.Cells[row, col]).Value2 = ((myExcel.Range)wsNew.Cells[row, col]).Value2 - ((myExcel.Range)wsBase.Cells[row, col]).Value2;
                        }
                    }
                }
            }


            // Copy formatting
            myExcel.Range range1 = wsBase.get_Range((myExcel.Range)wsBase.Cells[1, 1], (myExcel.Range)wsBase.Cells[maxR, maxC]);
            myExcel.Range range2 = wsDiff.get_Range((myExcel.Range)wsDiff.Cells[1, 1], (myExcel.Range)wsDiff.Cells[maxR, maxC]);
            range1.Copy();
            range2.PasteSpecial(myExcel.XlPasteType.xlPasteColumnWidths);

            excelApp.Workbooks[Book1].Close(false, false, false);
            excelApp.Workbooks[Book2].Close(false, false, false);

            string Book3 = "reporttestpc.xlsx"; //"reportBaseMinusNew.xlsx"
            if (File.Exists(currentWorkingDirectory + Book3))
            {
                File.Delete(currentWorkingDirectory + Book3);
            }

            excelWorkbook3.SaveAs(currentWorkingDirectory + Book3, Type.Missing, Type.Missing,
                                 Type.Missing, false, false, myExcel.XlSaveAsAccessMode.xlNoChange,
                                 Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

            //excelApp.Workbooks[Book3].Close(false, false, false);

            excelApp.Visible = true;
            return wereDifferences;
        }


        /// Determines whether two objects are equivalent
        /// Numbers are equivalent within the specified tolerance
        /// Strings are equivalent if they are identical
        /// obj1 and obj2 are the two objects being compared
        /// tolerance is the maximum difference between two numbers for them to be deemed equivalent

        private bool equiv(object obj1, object obj2, double tolerance)
        {
            if ((obj1 == null) && (obj2 == null))
            {
                return true;
            }
            else if ((obj1 == null) || (obj2 == null))
            {
                return false;
            }

            //if both are numeric
            if (IsNumeric(obj1))
            {
                if (IsNumeric(obj2))
                {
                    if (Math.Abs(Convert.ToDouble(obj2) - Convert.ToDouble(obj1)) < tolerance)
                    {
                        return true;    //If they are within tolerance
                    }
                    else
                    {
                        return false;   //If they are outside tolerance
                    }
                }
                else
                {
                    return false;       //If only one is numeric
                }
            }

            //Now assuming both are just random strings
            else
            {
                if ((string)obj1 == (string)obj2)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }


        // Test whether a given object represents a number
        internal static bool IsNumeric(object ObjectToTest)
        {
            if (ObjectToTest == null)
            {
                return false;
            }
            else
            {
                double OutValue;
                return double.TryParse(ObjectToTest.ToString().Trim(),
                    System.Globalization.NumberStyles.Any,
                    System.Globalization.CultureInfo.CurrentCulture,
                    out OutValue);
            }
        }

    ///

【问题讨论】:

  • 通常最好列出您尝试过的事情,以使其自己运行得更快。否则,我们只是为你做你的工作。是来帮忙的,不是来写你的程序的。
  • 你能分析一下大部分时间花在哪里吗?
  • 我的道歉,我认为很明显问题来自嵌套的 for 循环。我发布整个方法不是为了让别人为我做这项工作,而是为了更容易理解我在做什么以及如何改进它。我不认为这是超级快速的方法。然而,我希望有人能给我一点建议。

标签: c# .net excel c#-4.0


【解决方案1】:

建议一:

制作:

objNew.GetType().ToString() == "System.String"

这个:

objNew is string

很多清洁剂,对吧?也应该更快。

建议 2:

你经常打这个电话:

((myExcel.Range)wsDiff.Cells[row, col]

将结果存储在变量中并重复使用。所有这些索引器、属性和装箱/拆箱都会产生开销。对于您一遍又一遍地访问相同的 COM 方法、属性或索引器的任何地方也是如此。确保在 for 循环的范围之外声明这些变量,如果它们在循环的每次迭代中进出范围,将会影响性能。

建议 3:

您可以重复使用您的 Excel 应用程序对象吗?每次调用此方法时,您似乎都会创建一个新的。你能把它存储在你类的成员变量中吗?

【讨论】:

    【解决方案2】:

    您可以尝试使用 OleDb 读写 excel 文档。

    我不知道性能比较如何,但您可以对此进行分析。

    【讨论】:

      【解决方案3】:

      我认为您的 IsNumeric() 函数做了很多工作。简单地测试对象的类型怎么样?

      if(ObjectToTest == null) return false;  
      else if(ObjectToTest.GetType() == typeof(double)) return Convert.ToDouble(ObjectToTest);  
      else if(ObjectToTest.GetType() == typeof(decimal)) return Convert.ToDouble(ObjectToTest);  
      else return false;
      

      另外,我认为您只需要测试双数和小数。我可能错了。

      【讨论】:

      • 您也可以在这里有效地使用“is”运算符:(ObjectToTest 是双精度)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-09
      • 1970-01-01
      • 1970-01-01
      • 2014-06-08
      • 1970-01-01
      • 2016-09-05
      • 2021-08-04
      相关资源
      最近更新 更多