【问题标题】:EPPlus: Auto-save feature supported?EPPlus:支持自动保存功能吗?
【发布时间】:2015-06-30 21:10:05
【问题描述】:

我打算在我的 WPF 应用程序中使用 EPPlus(4.0.4 版本)库将我的实时数据导出到使用 C# .NET 的 Excel 工作表。然而,我的问题是针对 EPPLus 库的。

我浏览了 EPPlus 示例 (),您可以在其中使用 SetValue 将值写到工作表中。

问题在于,由于我的应用程序需要在可能的几天内写入实时数据(!),我想确保我的数据每隔一段时间保存一次,以避免在发生数据丢失的情况下丢失数据应用程序/系统崩溃。

通常,我希望有一个自动保存功能,其中可以保存当前状态,然后像往常一样继续添加新记录。

但是,EPPlus 似乎没有这个(?)......我将如何实现这一目标?

示例源代码

using (ExcelPackage package = new ExcelPackage())
{
      //Load the sheet with one string column, one date column and a few random numbers.
    var ws = package.Workbook.Worksheets.Add("Performance Test");

    //Format all cells
    ExcelRange cols = ws.Cells["A:XFD"];
    cols.Style.Fill.PatternType = ExcelFillStyle.Solid;
    cols.Style.Fill.BackgroundColor.SetColor(Color.LightGray);

    var rnd = new Random();                
    for (int row = 1; row <= Rows; row++)
    {
        ws.SetValue(row, 1, row);
        ws.SetValue(row, 2, string.Format("Row {0}", row));
        ws.SetValue(row, 3, DateTime.Today.AddDays(row));
        ws.SetValue(row, 4, rnd.NextDouble() * 10000);
        ws.SetValue(row, 5, rnd.NextDouble() * 100);
        ws.SetValue(row, 6, rnd.NextDouble() * 10);
        ws.SetValue(row, 7, rnd.NextDouble() * 78);
        ws.SetValue(row, 8, rnd.NextDouble() * 5300);
        ws.SetValue(row, 9, rnd.NextDouble() * 1250);
        ws.SetValue(row, 10, rnd.NextDouble() * 670);

        if (row % 10000 == 0)
        {
            Console.WriteLine("{0:HH.mm.ss}\tWriting row {1}...", DateTime.Now, row);

            //I need a way to save the existing data say every 10K records or so.

        }
    }             

    ws.Select("C2");
    Console.WriteLine("{0:HH.mm.ss}\tSaving...", DateTime.Now);
    package.Compression = CompressionLevel.BestSpeed;
    package.SaveAs(newFile); //this seems to be done only at the end of processing!
}

【问题讨论】:

    标签: c# export-to-excel epplus epplus-4


    【解决方案1】:

    为什么不在每批后保存并打开现有的 xls 并进行更新并再次保存?

    就像

    ExcelPackage package = new ExcelPackage(newFile);
    

    (*请注意这里newFile只是变量名,在这种情况下更像existingFile)

    您不会丢失工作表中已有的内容,您只需要找到最后一行即可从上次结束的地方继续:

    ws.Dimension.End.Row;
    

    作为奖励,您不会阻止用户访问文件(您的应用程序现在保持写入权限并阻止文件)以保存他自己的更改(比如说,在他添加了他想要从您的数据中获得的“免费且非常酷的图表”之后' :) )

    【讨论】:

    • 很好...特别。有用的是简要提及如何结束现有数据。
    【解决方案2】:

    AutoSave 通常用于基于用户界面的程序。 EPPlus 不是。

    你必须自己做。每隔一段时间就打电话给package.SaveAs(newFile);,也许在你的循环中。您似乎已经为此设置了if

    【讨论】:

    • 使用 package.SaveAs(newFile) 导致包被关闭!难道没有更好的办法吗?
    • 那你必须重新打开它。
    • hmmm... 看起来将这些数据保存到我自己的日志文件可能是有意义的,然后一旦测试完成,运行此代码以使用 EPPlus 将该数据导出到 excel! :( 感谢帕特里克提供的信息。
    • 这是一个很好的可能性,是的。这最大限度地减少了文件的曝光。
    【解决方案3】:

    我已经接受 Jan 'splite' Kondelík 的回答作为解决方案,因为它提供了解决问题所需的信息。

    但是,我发布了自己的示例,以帮助其他用户更快地获得 Jan 建议的解决方案。

    基本上,当重新打开文件时,您需要在 ExcelPackage() 构造函数中传递文件的名称。此外,您可以通过传递现有工作表的名称或如下索引来获取对所需工作表的引用

    package.Workbook.Worksheets["PerformanceTest"] 
    

    package.Workbook.Worksheets[1] //1 to n, 1 being base
    

    我发布了一个示例,帮助演示如何实现“自动保存”逻辑。希望这对其他人也有帮助。

    我用 C# 创建了一个控制台应用程序来演示这一点。

    示例代码

    Program.cs


    using System;
    using System.IO;
    
    namespace EPPlus_AutoSave_Excel_Export
    {
        class Program
        {
            static void Main(string[] args)
            {
                DirectoryInfo outputDir = new DirectoryInfo(@"c:\temp\Auto-Save");
    
                if (!outputDir.Exists) 
                    throw new Exception("outputDir does not exist!");
    
                Sample_Auto_Save obj = new Sample_Auto_Save(outputDir, 50000);
                obj.ExportWithAutoSave();
            }
        }
    }
    

    Sample_Auto_Save.cs


    using OfficeOpenXml;
    using OfficeOpenXml.Style;
    using System;
    using System.IO;
    using System.Drawing;
    
    namespace EPPlus_AutoSave_Excel_Export
    {
        class Sample_Auto_Save
        {
            int Rows;
            int nRowsWritten = 0;
            bool bAppendData = false;
            ExcelWorksheet ws;
            DirectoryInfo outputDir;
    
    
            public Sample_Auto_Save(DirectoryInfo outputDir, int Rows)
            {
                this.Rows = Rows;
                this.outputDir = outputDir;
            }
    
            public void ExportWithAutoSave()
            {
    
                FileInfo newFile = new FileInfo(outputDir.FullName + @"\Auto_Save_Export.xlsx");
                if (newFile.Exists)
                {
                    newFile.Delete();  // ensures we create a new workbook
                    newFile = new FileInfo(outputDir.FullName + @"\Auto_Save_Export.xlsx");
                }
    
                Console.WriteLine("{0:HH.mm.ss}\tStarting...", DateTime.Now);
                while (nRowsWritten < Rows)
                {
                    if (bAppendData == false)
                    {
                        using (ExcelPackage package = new ExcelPackage())
                        {
    
                            //Load the sheet with one string column, one date column and a few random numbers
                            ws = package.Workbook.Worksheets.Add("Performance Test");
                            InsertRows();
                            bAppendData = true;
                            AutoSave(newFile, package);
                        }
                    }
                    else
                    {
                        using (ExcelPackage package = new ExcelPackage(newFile))
                        {
                            Console.WriteLine("{0:HH.mm.ss}\tOpening existing file again!...", DateTime.Now);
                            ws = package.Workbook.Worksheets["Performance Test"];
    
                            InsertRows();
    
                            AutoSave(newFile, package);
                        }
                    }       
                }
                Console.WriteLine("{0:HH.mm.ss}\tDone!!", DateTime.Now);           
            }
    
            private void AutoSave(FileInfo newFile, ExcelPackage package)
            {
                ws.Select("C2");
                Console.WriteLine("{0:HH.mm.ss}\tAuto-Saving...", DateTime.Now);
                package.Compression = CompressionLevel.BestSpeed;
                package.SaveAs(newFile);
                bAppendData = true;
            }
    
            private void InsertRows()
            {
    
                //Format all cells
                ExcelRange cols = ws.Cells["A:XFD"];
                cols.Style.Fill.PatternType = ExcelFillStyle.Solid;
                cols.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
    
                var rnd = new Random();
                int startRow;
                if (ws.Dimension == null)
                    startRow = 0;
                else
                    startRow = ws.Dimension.End.Row;
                for (int row = startRow + 1; row <= Rows; row++, nRowsWritten++)
                {
                    ws.SetValue(row, 1, row);                               //The SetValue method is a little bit faster than using the Value property
                    ws.SetValue(row, 2, string.Format("Row {0}", row));
                    ws.SetValue(row, 3, DateTime.Now.ToShortTimeString());
                    ws.SetValue(row, 4, rnd.NextDouble() * 10000);
    
    
                    if (row % (Rows/5) == 0)
                    {
                        Console.WriteLine("{0:HH.mm.ss}\tWritten {1} records!...", DateTime.Now, row);
                        nRowsWritten++;
                        return;
                    }
                }
            }
        }
    }
    

    更新: 看起来自动保存大文件的开销非常高。在与 Jan 和 Patrick 讨论之后,我最终意识到最好将我所有的实时数据写入一个单独的数据文件,最后在我的测试结束时使用 EPPlus 导出到 excel。这将是最快、最简单的方法!

    或者,如果并非强制要求所有数据都应存在于一个文件中,请考虑将数据拆分到多个 Excel 文件中。例如,您可以为每个文件保存 10K 条记录,这样可以同时确保速度、低内存要求和数据安全。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-30
      • 2011-11-13
      • 1970-01-01
      • 1970-01-01
      • 2011-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多