EPPlus:支持自动保存功能吗?

EPPlus: Auto-save feature supported?

我计划在我的 WPF 应用程序中使用 EPPlus(4.0.4 版)库将我的实时数据导出到 excel sheet 使用 C# .NET。然而,我的问题是针对 EPPLus 库的。

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

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

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

但是,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!
}

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

你必须自己做。每隔一段时间就调用 package.SaveAs(newFile); ,也许在你的循环中。您似乎已经为此准备好了 if

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

喜欢

ExcelPackage package = new ExcelPackage(newFile);

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

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

ws.Dimension.End.Row;

作为奖励,您不会阻止用户访问文件(您的应用程序现在保留写入权限并阻止文件)以保存他自己的更改(假设,在他添加 'free and very cool graph he want from your data' :) )

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

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

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

package.Workbook.Worksheets["PerformanceTest"] 

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

我正在发布一个示例,它有助于演示如何实现 "Auto-save" 逻辑。希望这对其他人也有帮助。

我用 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 条记录,这样,您可以同时确保速度、低内存需求和数据安全。