EPPLS:支持自动保存功能

本文关键字:保存 功能 支持 EPPLS | 更新日期: 2023-09-27 18:00:31

我计划使用EPPlus(4.0.4版本)库,在WPF应用程序中使用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!
}

EPPLS:支持自动保存功能

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

就像

ExcelPackage package = new ExcelPackage(newFile);

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

你不会丢失你已经在纸上的东西,你只需要找到最后一行就可以继续上次结束的地方:

ws.Dimension.End.Row;

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

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

你必须自己做。只要每隔一段时间打一次package.SaveAs(newFile);,也许在你的循环中。你似乎已经有了if

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

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

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

package.Workbook.Worksheets["PerformanceTest"] 

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

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

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

样本代码

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