Information:
MS Excel Version Installed: Excel 2013 (Can try to change if required)
Reference Library Used: Microsoft Excel 15.0 Object Library (version 1.8)
.Net Framework: 4.7.2 (Cannot change)
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. 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 --
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();
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. Your comments got me thinking that did I really open the file "AGAIN" ?
I say "again" because this is what had happened...
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)
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).
And now I had several instances of open excel objects which were not closed, because by now I had debugged several times. And since then no matter where I put excel.Quit(), that instance was somehow open somewhere for some reason.
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.
Now I created a public method inside this FileManager class called Close() which looks like:
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.
And now its working fine. :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.