加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 解析大型Excel文件列表失败

发布时间:2020-12-15 22:05:36 所属栏目:百科 来源:网络整理
导读:这是一个C#/ VSTO程序.我一直在研究数据捕获项目.范围基本上是“由各种第三方公司发送的过程Excel文件”.实际上,这意味着: 通过搜索方法找到包含我想要的数据的列. 从工作簿中获取数据 清理数据,运行一些计算等 将清理后的数据输出到新工作簿中 我编写的程
这是一个C#/ VSTO程序.我一直在研究数据捕获项目.范围基本上是“由各种第三方公司发送的过程Excel文件”.实际上,这意味着:

>通过搜索方法找到包含我想要的数据的列.
>从工作簿中获取数据
>清理数据,运行一些计算等
>将清理后的数据输出到新工作簿中

我编写的程序非常适合中小型数据集,约25个工作簿,总共有大约1000行的相关数据.我正在从这些工作簿中获取7列数据.我有一个边缘案例,偶尔我需要运行一个更大的数据集,~50个工作簿,总共有大约8,000行的相关数据(可能还有另外?2000个重复数据,我也必须删除).

我目前正在通过Parallel.ForEach循环放置文件列表,其中我打开一个新的Excel.Application()来处理具有多个ActiveSheets的每个文件.并行进程在较小的数据集上运行得比按顺序遍历每个数据集要快得多.但是在更大的数据集上,我似乎碰壁了.

我开始收到消息:Microsoft Excel正在等待另一个应用程序完成OLE操作,最终它失败了.切换回顺序foreach确实允许程序完成,但它只是研磨 – 从并行中型数据集的1-3分钟到顺序大型数据集的20分钟.如果我将ParallelOptions.MaxDegreeOfParallelism设置为10,它将完成循环,但仍需要15分钟.如果我将其设置为15,则会失败.如果我不需要,我也真的不喜欢弄乱TPL设置.我也试过插入一个Thread.Sleep来手动减慢速度,但这只会让故障进一步发生.

我关闭工作簿,退出应用程序,然后将ReleaseComObject关闭到Excel对象,并在每个循环结束时使用GC.Collect和GC.WaitForPendingFinalizers.

我现在的想法是:

>将列表分成两半并单独运行
>并行打开一些新的Excel.Application(),但是在该Excel实例内部顺序运行一个文件列表(所以有点像#1,但是使用不同的路径)
>按文件大小分隔列表,并独立/顺序运行一小组非常大的文件,运行其余文件,因为我一直在

我希望得到一些帮助的事情:

>关于真正确保我的记忆被清除的建议(也许Process.Id在所有的开始和结束时都被扭曲了?)
>关于订购并行流程的建议 – 我想知道我是否可以先抛出’大’人,这将使更长时间的流程更加稳定.

我一直在寻找:http://reedcopsey.com/2010/01/26/parallelism-in-net-part-5-partitioning-of-work/,他说“有了你的工作的先验知识,有可能比默认的分区器更有意义地划分数据.”但我真的很难知道分区是否有意义.

真的很感激任何见解!

UPDATE

因此,作为一般规则,我对Excel 2010进行了测试,因为我们在此处使用了2010和2013.我在2013年运行它并且它工作正常 – 运行时间大约4分钟,这是我所期望的.在我放弃2010兼容性之前,还有其他想法吗? 2010机器是64位计算机,64位Office,2013计算机是64位计算机,32位Office.这有关系吗?

解决方法

几年前,我使用excel文件和自动化.然后我遇到了在任务管理器中拥有僵尸进程的问题.虽然我们的计划已经结束,但我认为我退出了正常,但这些流程并没有放弃.

解决方案不是我喜欢的东西,但它是有效的.我可以总结这样的解决方案.

1)永远不要连续使用两个点:

workBook.ActiveSheet.PageSetup

而是使用变量..当你完成重新传递并将它们归零时.

示例:而不是这样做:

m_currentWorkBook.ActiveSheet.PageSetup.LeftFooter = str.ToString();

遵循此功能中的做法. (此功能为excel页脚添加条形码.)

private bool SetBarcode(string text)
    {
            Excel._Worksheet sheet;
            sheet = (Excel._Worksheet)m_currentWorkbook.ActiveSheet;
            try
            {
                StringBuilder str = new StringBuilder();
                str.Append(@"&""IDAutomationHC39M,Regular""&22(");
                str.Append(text);
                str.Append(")");

                Excel.PageSetup setup;
                setup = sheet.PageSetup;
                try
                {
                    setup.LeftFooter = str.ToString();
                }
                finally
                {
                    RemoveReference(setup);
                    setup = null;
                }
            }
            finally
            {
                RemoveReference(sheet);
                sheet = null;
            }

            return true;

    }

这是RemoveReference函数(在此函数中放置null不起作用)

private void RemoveReference(object o)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
        }
        catch
        { }
        finally
        {
            o = null;
        }
    }

如果您遵循这种模式,它保证没有泄漏,没有僵尸进程等.

2)为了创建excel文件你可以使用excel应用程序,但是为了从excel获取数据,我建议使用OleDB.您可以像数据库一样使用excel,并使用sql查询,数据表等从中获取数据.

示例代码:(而不是填充数据集,您可以使用datareader获取内存性能)

private List<DataTable> getMovieTables()
    {
        List<DataTable> movieTables = new List<DataTable>();
        var connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excelFilePath + ";Extended Properties="Excel 12.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text""; ;
        using (var conn = new OleDbConnection(connectionString))
        {
            conn.Open();

            DataRowCollection sheets = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,new object[] { null,null,"TABLE" }).Rows;

            foreach (DataRow sheet in sheets)
            {

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText = "SELECT * FROM [" + sheet["TABLE_NAME"].ToString() + "] ";

                    var adapter = new OleDbDataAdapter(cmd);
                    var ds = new DataSet();
                    try
                    {
                        adapter.Fill(ds);
                        movieTables.Add(ds.Tables[0]);
                    }
                    catch (Exception ex)
                    {
                        //Debug.WriteLine(ex.ToString());
                        continue;
                    }
                }
            }
        }
        return movieTables;
    }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读