简体   繁体   English

在 c# 控制台应用程序中更新 Excel 文件后无法保存

[英]Cannot save Excel file after updating it in c# console app

Information:信息:

MS Excel Version Installed: Excel 2013 (Can try to change if required)已安装 MS Excel 版本:Excel 2013(如果需要,可以尝试更改)

Reference Library Used: Microsoft Excel 15.0 Object Library (version 1.8)使用的参考库:Microsoft Excel 15.0 对象库(1.8 版)

.Net Framework: 4.7.2 (Cannot change) .Net 框架:4.7.2(无法更改)

Application Type: Console Application (Cannot change)应用程序类型:控制台应用程序(无法更改)

What I need:我需要的:

So I have an excel workbook, which already has about 8000 rows each in first 2 sheets and some graphs in 4 other sheets.所以我有一个 excel 工作簿,它在前 2 个工作表中已经有大约 8000 行,在其他 4 个工作表中已经有一些图表。 I need to add this data to the bottom of the existing data in one of the first 2 sheets, do a refresh, save it and close it.我需要将此数据添加到前两张工作表之一中现有数据的底部,进行刷新,保存并关闭它。

This is what im doing:这就是我在做什么:

    using MSExcel = Microsoft.Office.Interop.Excel;

In the class constructor--在类构造函数中——

    public UsageReportFileManager(string reportFolderPath)
    {
        excel = new MSExcel.Application();

        if (excel == null)
        {
            log.Error("-E-Unable to create report!!");
            throw new Exception("Microsoft excel is not installed on the client machine");
        }
        InitializeWorkbook();
    }

the Initialize Workbook function---初始化工作簿功能---

    private void InitializeWorkbook()
    {
        if (excel != null)
        {
            var filePath = GetResultPath(); //This returns a path which ends with .xlsx and it is a path to the existing file.

            if (!File.Exists(filePath)) //This is just handling a situation in case the actual file is missing.
            {
                //Create copy from template
                var templatePath = GetTemplateFilePath(); // this is not a excel template btw, its a empty workbook with formulas.
                File.Copy(templatePath, filePath);
                // Till here its working and new file is created if original file is missing
            }

            var missing = Missing.Value;
            _workbook = excel.Workbooks.Open(Filename: filePath, 
                UpdateLinks: missing, 
                ReadOnly: false, 
                Format: missing, 
                Password: missing, 
                WriteResPassword: missing, 
                IgnoreReadOnlyRecommended: true, 
                Origin: missing, 
                Delimiter: missing, 
                Editable: true, 
                Notify: missing, 
                Converter: missing, 
                AddToMru: true,
                Local: true
                );
        }
    }

In a separate function in this class which is called from Program.cs after this class is Initialized --在这个类中的一个单独的函数中,它在这个类被初始化后从 Program.cs 调用——

    public void UpdateLoginRawDataToWorkbook(List<HubAuditEvent> lstLoginData)
    {
            var dtLoginData = ConvertDataListToDatatable(lstLoginData); -- I will be getting more than 1500 rows here.

            if (dtLoginData.Rows.Count > 0)
            {
                MSExcel.Worksheet sheet = _workbook.Sheets["SheetAlreadyHasData"] as MSExcel.Worksheet;

                MSExcel.Range lastCell = sheet.Cells.Find(
                    "*",
                    Missing.Value,
                    Missing.Value,
                    Missing.Value,
                    MSExcel.XlSearchOrder.xlByRows,
                    MSExcel.XlSearchDirection.xlPrevious,
                    false,
                    Missing.Value,
                    Missing.Value);

                int lastRow = lastCell.Row;

                for (int i = 0; i < dtLoginData.Rows.Count; i++)
                {
                    int row = lastRow + i + 1;
                    for (int j = 0; j < dtLoginData.Columns.Count; j++)
                    {
                        var col = j + 1;
                        sheet.Cells[row, col] = dtLoginData.Rows[i][j].ToString();
                    }
                }

                _workbook.RefreshAll();
                excel.Calculate();
                _workbook.Save(); <-- I get an exception here saying Cannot Save Read-Only file ..
                _workbook.Close(true);
                excel.Quit();
      }

I get an exception at the _workbook.Save();我在_workbook.Save();处得到一个异常_workbook.Save(); line saying Cannot Save Read-Only file ..行说无法保存只读文件..

Okay so I post this as an answer and not a comment, because I believe many of us might be doing this same thing without even realising it.好的,所以我将其发布为答案而不是评论,因为我相信我们中的许多人可能会在没有意识到的情况下做同样的事情。

Special thanks to @PanagiotisKanavos and @MikeJ: You just saved my day.特别感谢@PanagiotisKanavos 和@MikeJ:你们拯救了我的一天。 Your comments got me thinking that did I really open the file "AGAIN" ?你的评论让我觉得我真的打开了“再次”文件?

I say "again" because this is what had happened...我说“再次”因为这就是发生的事情......

  1. So I open the file, check if its read-only and run my console app.所以我打开文件,检查它是否只读并运行我的控制台应用程序。 (See here I forget to close the workbook on my desktop app) (见这里我忘记关​​闭桌面应用程序上的工作簿)

  2. Then in the middle of the debugging I get the exception that its open, so I stop the debugging the moment I see the exception.然后在调试过程中,我收到了打开的异常,所以我在看到异常的那一刻就停止调试。 (Here first thing, because I was just testing I forgot to put the excel.Quit() in the finally block-- which I realize now is very very very important. And even if I had it in my finally block, the second mistake I was doing is I was stopping the app the moment I got the exception). (这是第一件事,因为我只是在测试,我忘记将 excel.Quit() 放在 finally 块中——我现在意识到这是非常非常重要的。即使我在 finally 块中拥有它,第二个错误我正在做的是我在遇到异常的那一刻就停止了应用程序)。

  3. And now I had several instances of open excel objects which were not closed, because by now I had debugged several times.现在我有几个未关闭的打开 excel 对象实例,因为到目前为止我已经调试了几次。 And since then no matter where I put excel.Quit(), that instance was somehow open somewhere for some reason.从那时起,无论我将 excel.Quit() 放在哪里,该实例都会出于某种原因在某处打开。

  4. Then I checked your comments and tried opening manually again and got the same error message that its read-only.然后我检查了您的评论并尝试再次手动打开并收到与其只读相同的错误消息。 And it was all crystal clear then.那时一切都非常清楚。

  5. Now I created a public method inside this FileManager class called Close() which looks like:现在我在 FileManager 类中创建了一个名为 Close() 的公共方法,它看起来像:

     public void Close() { if(excel != null && _workbook != null) { _workbook.Close(true); excel.Quit(); } }

Now I called this Close() method from the finally block in my Program.cs class.现在我从 Program.cs 类的 finally 块中调用了这个 Close() 方法。

  1. Then I had to literally restart my machine to release that lock :D.然后我不得不重新启动我的机器来释放那个锁:D。

And now its working fine.现在它工作正常。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM