Excel使用NPOI-效率

b^3

新成员
已加入
2020年4月6日
留言内容
4
编程经验
10+
C#的新手,我的第一个项目是读取Excel(.xlsx)文件。
我正在从电子表格中读取每个单元格,然后进行格式化以将其输出为CSV文件。目前,我只是写信给STDOUT。
我的第一次尝试只是拉出所有单元格条目并处理了.ToString()。可以理解,这返回公式,而我真正想要的是公式创建的值。
因此,我放入其他代码来测试条目是否为值类型,然后如上所述通过.ToString()处理,否则使用.NumericCellValue.ToString()代替。
但是,添加此检查后,处理时间增加了8倍(例如,<2分钟到〜15分钟)。这是一个合理的期望还是可以使其更有效率?
这是我的注释代码:
C#:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using NPOI.XSSF.UserModel;

using NPOI.HSSF.UserModel;

using NPOI.SS.UserModel;

using System.IO;



namespace ExcelReader

{

    class ReadDataNPOI

    {

        IWorkbook Book;

        ISheet DesiredSheet;

        const string Delimiter = ",";

        DateTime StartTime = DateTime.Now;

        StringBuilder RowContent = new StringBuilder(String.Empty);

        int LNoRow = 8, LNoCol = 1, CustDRow = 7, CustDCol = 1;

        string LNo, CustD, IntD = "DRDZ-050-120-C_HEC", GlobalD = "GlobalD62941.4Z";  //Need to get the IntD and GlobalD from MES.

        string Filename = "";

        string LInfo = "";

      

        public ReadDataNPOI(string path, int Sheet)

        {

            try

            {

                FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);

                Filename = path;

                try

                {

                    Book = new XSSFWorkbook(fs);

                }

                catch

                {

                    Book = null;

                }

                // If reading fails, try to read workbook as XLS:

                if (Book == null)

                {

                    Book = new HSSFWorkbook(fs);

                }





            }

            catch (Exception ex)

            {

                Console.WriteLine(ex.Message, "Excel read error");

                return;

            }

            try

            {

                DesiredSheet = Book.GetSheetAt(Sheet);

            }

            catch (Exception ex)           {

                Console.WriteLine(ex.Message, "ERROR: Sheet read error or not available.");

                return;

            }



        }

        public  string ReadWorkbook(int i, int j)

        {

            //Get L number from spreadsheet.

            if (null != DesiredSheet.GetRow(LNoRow).GetCell(LNoCol) && !string.IsNullOrEmpty(DesiredSheet.GetRow(LNoRow).GetCell(LNoCol).ToString()))

            {

                LNo = DesiredSheet.GetRow(LNoRow).GetCell(LNoCol).ToString();

            }

            else

            {

                if (null != DesiredSheet.GetRow(LNoRow - 1).GetCell(LNoCol) && !string.IsNullOrEmpty(DesiredSheet.GetRow(LNoRow - 1).GetCell(LNoCol).ToString()))

                    LNo = DesiredSheet.GetRow(LNoRow - 1).GetCell(LNoCol).ToString();

            }

            if (LNo == null)

            {

                Console.WriteLine("No L number recorded in file:" + Filename);

                return "";

            }



            //Get CustD from spreadsheet.

            //This checks to see if the L Number is in its proper cell; if so that implies the CustD will also

            //be in its proper cell.  This will hopefully handle the older files and the newer files with L number location correction.

            if (null != DesiredSheet.GetRow(LNoRow).GetCell(LNoCol) && !string.IsNullOrEmpty(DesiredSheet.GetRow(LNoRow).GetCell(LNoCol).ToString()))

            {

                CustD = DesiredSheet.GetRow(CustDRow).GetCell(CustDCol).ToString();

            }

            else

            {

                CustD = "";

            }



            //Console.WriteLine(LNo + Delimiter + IntD + Delimiter + GlobalD + Delimiter + CustD + System.Environment.NewLine);

            LInfo = LNo + Delimiter + IntD + Delimiter + GlobalD + Delimiter + CustD + Delimiter;



            for (int Row=30; Row <= DesiredSheet.LastRowNum; Row++)

            // NOTE:  This is hard coded for now.  Will later be defined in a global variable.

            //  This is where the main data section begins in all workbooks to be processed.

            {

                RowContent.Append(LInfo);



                if (DesiredSheet.GetRow(Row) != null)

                {

                    for (int Col = 0; Col <= DesiredSheet.GetRow(Row).LastCellNum; Col++)

                    {

                      

                        if (null != DesiredSheet.GetRow(Row).GetCell(Col) && !string.IsNullOrEmpty(DesiredSheet.GetRow(Row).GetCell(Col).ToString()))

                        {

                            CurrentCell = DesiredSheet.GetRow(Row).GetCell(Col);

                            // Before checking for IsValueType

                            // RowContent.Append(CurrentCell.NumericCellValue.ToString());

                            // This is now the exception to IsValueType.

                            if (CurrentCell.GetType().IsValueType)

                            {

                                RowContent.Append(CurrentCell.ToString());

                            }

                            else

                            {

                                RowContent.Append(CurrentCell.NumericCellValue.ToString());

                            }

                            if (Col < DesiredSheet.GetRow(Row).LastCellNum-1)

                            {

                                RowContent.Append(Delimiter);

                            }

                            //The next else was used to place all data in one long string.  Took too long.

                            //else

                            //{

                            //    Console.WriteLine(DesiredSheet.GetRow(Row).LastCellNum);

                            //    RowContent.Append(System.Environment.NewLine);

                            //}

                        }



                    }

                    Console.WriteLine(RowContent);

                    RowContent.Clear();

                }

            }

            Book.Close();

            Console.WriteLine("Start: " + StartTime);

            DateTime EndTime = DateTime.Now;

            Console.WriteLine("End: " + EndTime);



            return String.Empty;

        }

    }

}

任何反馈,不胜感激。
 
Last edited:

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
出于好奇...如果您使用C#编写代码,为什么要使用POI?这是Apache POI网站上的前几句话:
Apache POI-Microsoft文档的Java API
如果使用的是C#,请使用C#为什么要调用Java库?
 

b^3

新成员
已加入
2020年4月6日
留言内容
4
编程经验
10+
@跳伞,有效问题。您会推荐哪些库?
关于NPOI,这是我最好的回答:NPOI的NuGet项目描述是"该项目是Apache Foundation提供的POI的.NET端口。 NPOI可以读写xls(Excel 97-2003),xlsx(Excel 2007+)和docx(Word 2007+)".
我从Microsoft.Office.Interop .Excel开始,但是,这要求在运行该程序的任何系统上都必须安装Excel。由于工作环境的原因,这可能不适合。另外,互操作库比NPOI慢得多。使用NPOI,使用互操作库耗时约35分钟,而用时不到2分钟。我相信,这部分是因为使用NPOI时程序不必启动Excel的后台实例。

自从首次发布以来,我已经进行了一些改进,并且处理时间有所缩短,但是如果有人对如何提高效率有想法,我仍然会对您的想法感兴趣。

谢谢。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
是什么让您认为您需要图书馆?
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
不是特别。我认为我的问题很深刻。
 
Last edited:

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
如果您只需要处理2007年及以后的Office文档(.xlsx)以提高效率,我建议您使用.NET Framework SDK附带的OpenXML。它与Microsoft使用的库相同。它非常高效,并且已经进行了许多性能测试(对于Office认为很关键的方案)。

(直接)使用OpenXML的缺点是,尽管就操作而言它非常有效,但就开发人员时间而言却不是很有效。您将必须了解如何以最低级别存储Office文档的复杂性。有很多的"magic numbers"以及文档中嵌入的奇怪的XML继承关系。更糟糕的是,文档是不相干的。您需要的所有信息都存在,但可能不在您希望找到的地方。 (我是根据经验讲的。)

因此,实质上,使用OpenXML就像在汇编中进行编程一样。强大的力量。效率很高。但也需要大量的开发人员时间。

因此,如果您想要没有学习曲线那么陡峭的东西,那么我工作地点的几个团队对Aspose的速度非常满意。 Aspose还支持较旧的文档格式。作为必须密切关注运行这些团队代码的服务器的人,我可以说我对他们的应用程序的内存和CPU使用率感到非常满意。我还没有看到他们的应用程序成为猪,不像其他使用其他两个不同库的应用程序,这些库的名称现在就让我逃脱了。
 
最佳 底部