【问题标题】:Is there a way to fill out an Excel workbook without involving Excel itself? Or can I force Excel to quit?有没有办法在不涉及 Excel 本身的情况下填写 Excel 工作簿?或者我可以强制 Excel 退出吗?
【发布时间】:2019-05-03 20:52:04
【问题描述】:

我正在创建一个网页来选择数据以下载 Excel 工作簿(包含宏),并将该数据填充到相应的单元格中。

我得到了一个 .vbs 作为填写 Excel 工作簿的起点。

.vbs中,原程序员调用

Set objExcel =  CreateObject("Excel.Application")
set ObjWorkbook =objExcel.Workbooks.Open(blankFile)
`...
objWorkbook.Saveas(outputFile)
objExcel.Quit

我正在尝试使用 C# 和 MVC 制作网页,因此我查看了 Excel.Application 并找到了 thisthis。我开发了一个动作,只是为了测试一下:

public FileResult filledOutWorkbook()
{
    Excel.Application oXL;
    Excel._Workbook oWB;
    Excel._Worksheet oSheet;
    Excel.Range oRng;

    oXL = new Excel.Application();
    oXL.Visible = false;

    oWB = oXL.Workbooks.Open(Server.MapPath("~/Content/Worksheet2.xlsm"));
    oSheet = oWB.Sheets["Information Sheet"];

    oSheet.Range["V2"].Value2 = "customer test lol";

    if (!Directory.Exists(Server.MapPath("~/App_Data/temp")))
    {
        Directory.CreateDirectory(Server.MapPath("~/App_Data/temp"));
    }
    var filename = Server.MapPath("~/App_Data/temp/") + DateTime.Now.ToString("o").Replace(":", "") + ".xlsm";
    oWB.SaveCopyAs(filename);

    oXL.Visible = false;
    oXL.Quit();

    return File(filename, "application/vnd.ms-excel.sheet.macroEnabled.12", "Worksheet.xlsm");
}

(我将执行计划任务或其他事情来清除这些,因为我很确定我不能只获取文件的字节流。)

问题是,这不会关闭 Excel。显然 C# 没有与理解 Excel 工作簿格式的库进行交互,您正在自动化 Excel。我会在生产服务器上安装 Excel,但是当我告诉它退出 Excel 时,它并没有退出。它询问用户是否要保存对模板文档的更改。我不知道这个页面会被使用多少次,但我认为在服务器上多次单击“否”以释放内存是一种不好的做法。

我可以绕过这个吗?有没有比 COM 对象 Microsoft.Office.Interop.Excel 更好的库?我可以强制 Excel 关闭还是最好的办法是在 VB 中编写所有 Excel 交互并从控制器操作中调用它?

【问题讨论】:

  • 您是否尝试过强制关闭而不保存?在oXL.Quit(); 之前尝试WB.Close(false);
  • 你从未释放你获得的 COM 对象。除非您这样做,否则 excel 将永远不会完全退出
  • @Steve 设置对null 的引用,使用GC.Collect,并调用Quit 就足以清理Excel。
  • @DaveCousineau 并非总是如此。你可能会以这种方式遇到内存损坏。过去有过这种经历
  • @Steve“内存损坏”?我有几十个应用程序可以毫无问题地执行此操作。

标签: c# excel


【解决方案1】:

作为曾经使用过 Microsoft Excel 互操作性库并深受其害的人,我很高兴您正在寻找替代方案。

不要误会我的意思。如果您尝试使用少量数据自动执行一些简单的任务,互操作性库非常有用。但是当它涉及大量数据时,它的速度非常慢。如果您希望在 Web 服务器上使用此功能,则还需要在服务器上安装 Excel。

我建议你使用 ClosedXML。它是开源和 MIT 许可的。它基本上是围绕 OpenXML 的包装器。它也非常易于使用,速度更快,并且不需要在服务器上安装 Excel

https://github.com/ClosedXML/ClosedXML

【讨论】:

  • 我用过一点ClosedXML,挺好用的。我比较熟悉 EPPLus,也就是指甲。如果您还没有尝试过,请尝试一下。正如您在使用 ClosedXML 时所说的那样,它确实消除了使用互操作的大部分痛苦。互操作的真正痛苦之一是无法使用 Intellisense。
  • 同意尽可能避免在您的服务器上安装 Excel,这也会使许可变得非常复杂,MS 强烈建议不要这样做:serverfault.com/a/375417Current licensing guidelines prevent Office applications from being used on a server to service client requests, unless those clients themselves have licensed copies of Office.
  • 互操作的真正痛苦之一是无法使用 Intellisense。 我怎么能忘记这一点?在使用 Interop 库时,我花在查看可能的方法和属性而不是实际工作上的时间非常高
【解决方案2】:

如果它要求您保存,则表示它认为工作簿有未保存的更改。只需关闭工作簿,退出前不要保存更改:

oWB.Close(false);

您可能还需要关闭第一个默认工作簿,事实上这可能实际上是导致保存消息的那个。查找另一个工作簿并将其关闭而不保存。比如:

oXL.Workbooks[0].Close(false);

或者只是枚举集合并关闭所有集合。

这将取决于 Excel 所处的实际状态。如果您不确定该怎么做,请显示 Excel 而不是关闭它,并尝试查看它认为未保存的内容并决定是否要保存或丢弃。

【讨论】:

    【解决方案3】:

    您在这里有两个很好的答案,但作为替代方案,您也可以告诉 Excel 暂停警告。这在您执行通常会提示对话框的操作时很有帮助,例如在已存在的文件上“另存为”。

    Excel 对象上的DisplayAlerts 属性控制这一点,默认情况下为真。将其更改为 false 将暂停警报,因此这也应该有效:

    application.DisplayAlerts = false;
    application.Quit();
    application.DisplayAlerts = true;
    

    【讨论】:

      【解决方案4】:

      我建议您在这里采取不同的方法。我会在 excel 工作簿中创建一个选项卡,用户可以在其中输入驱动数据选择的选择。然后编写一些脚本来使用这些设置从 Web 服务中提取数据。以这篇文章为例:https://atinkerersnotebook.com/2012/12/28/creating-consuming-web-services-with-excel/

      现在您所要做的就是编写 Web 服务来返回请求的数据。

      【讨论】:

        【解决方案5】:

        我想建议一些不同的方法来生成一个 excel 文件。对于中等复杂度的工作表,使用报表设计器来设计报表,然后将其导出到 Excel 文件要容易得多。它可以生成到流中,您甚至不必生成文件。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-23
          • 2010-11-27
          • 2013-01-23
          • 1970-01-01
          相关资源
          最近更新 更多