I working with windows application and processing large excel file. I need to save 100k rows from datatable to excel file.
Currently my create excel function only support 65,500 rows only?
But I need to save excel file more than that. Is it possible?
If yes then, Kindly give the source?
Here is my code
public static void ExportDataSetToExcel(DataTable dt, int index, string strFilePathName)
{
Console.WriteLine("Creating Output Excel file");
string fileFomat = getExcelFileName(index) + (DateTime.Now.ToString("yyyyMMddTHHmmss"));
Microsoft.Office.Interop.Excel.Application objXL = null;
Microsoft.Office.Interop.Excel.Workbook objWB = null;
try
{
objXL = new Microsoft.Office.Interop.Excel.Application();
objWB = objXL.Workbooks.Add(1);
int sheetcount = 1;
Microsoft.Office.Interop.Excel.Worksheet objSHT = (Microsoft.Office.Interop.Excel.Worksheet)objWB.Sheets.Add();
Microsoft.Office.Interop.Excel.Range cells = objSHT.Cells;
cells.NumberFormat = "#";
//formatRange = objSHT.get_Range("b1",Type.Missing);
//formatRange.EntireRow.Font.Bold = true;
objSHT.Name = "RunOrderSheet";
for (int j = 0; j < dt.Rows.Count; j++)
{
for (int i = 0; i < dt.Columns.Count; i++)
{
//Condition to put column names in 1st row
//Excel work book indexes start from 1,1 and not 0,0
if (j == 0)
{
objSHT.Cells[1, i + 1] = dt.Columns[i].ColumnName.ToString();
}
//Writing down data
objSHT.Cells[j + 2, i + 1] = dt.Rows[j][i].ToString();
}
}
sheetcount++;
objWB.Saved = true;
objWB.SaveCopyAs(strFilePathName.Trim() + fileFomat.Trim() + ".xlsx");
objWB.Close();
objXL.Quit();
Console.WriteLine("Process done");
}
catch (Exception ex)
{
objWB.Saved = true;
objWB.Close();
objXL.Quit();
log.Error(ex.Message);
}
}
Excel and the COM interface with C# absolutely will support more than 65k lines. Just to prove that it's possible, run the following code:
public static void ExportDataSetToExcel()
{
Excel.Application objXL = null;
Excel.Workbook objWB = null;
objXL = new Microsoft.Office.Interop.Excel.Application();
objXL.Visible = true;
objWB = objXL.Workbooks.Add(1);
Excel.Worksheet objSHT = objWB.Sheets.Add();
for (int row = 1; row < 100000; row++)
{
objSHT.Cells[row, 1].Value2 = row;
}
objWB.SaveAs("c:\test\test.xlsx", Excel.XlFileFormat.xlOpenXMLWorkbook);
objWB.Close();
objXL.Quit();
}
Which leads me to several possibilities as to what your issue might be, in order of my suspicions (first being what I think is the most likely):
Since you have a try/catch block that is very nicely trapping errors and making sure that anything that happens within your loop while still saving the file, something is tripping the proverbial circuit breaker. While I don't see any glaring errors, it could be anything. Put a breakpoint within the catch block and see what ex contains. Also, make note of the specific record that is causing the error so you can step through just that one record and see where it occurs.
I noticed you are using SaveCopyAs rather than SaveAs. SaveCopyAs automatically saves in the exact same format as the original. I would think your Excel comes up with the default xlsx, but I certainly can't guarantee that. Using SaveAs with the explicit file format will guarantee it is saved in a format that supports more than 65k lines:
.
objWB.SaveAs("c:\test\test.xlsx", Excel.XlFileFormat.xlOpenXMLWorkbook);
Without knowing how large your datatable is, it might simply be a memory issue also that's tripping the try/catch.
Related
I am writing a winform app that reads data from an sql database, paste it into excel and then saves the file in a given location.
My current issue is i'm encountering system error : 0x800AC472 when saving down the excel file.
So far I have tried adding
GC.Collect();
GC.WaitForPendingFinalizers();
to the on click method, after calling the excel save function.
From my googling it seems as though it may be due to the COM object not being removed after usage? these GC methods were meant to clear this, but it doesn't seem to be working properly. The reason I think it's not working properly is that there is still a microsoftoffice.exe process running in task manager after executing the code and receiving the error.
Something else worthy of mention is that if i wrap the code in a try-catch, the error is pasted to the console and the excel file is saved without issue, the only issue being that the process is still running in the task manager.
Is anyone here able to help me isolate the issue in my code causing this error? Thank you.
Here is the code that is called upon button press;
else if (((DataGridView)sender).Columns[e.ColumnIndex].DataPropertyName == "Run")
{
// return SQL into datatable
var returnedDT = SQLAcess.SQLtoDataTable(dataGridView1[0, e.RowIndex].Value.ToString()!);
//find item to open
string loadstring = DataGridClass.CellColumn(dataGridView1, "Load_Location", e.RowIndex);
//finds workbook to paste into.
var SettingsDataset = XMLData.ReturnXMLDataset(2);
var workbookstring = XMLData.returnXMLcellwithcolumnname(SettingsDataset, "Data_Dump_Worksheet_name", e.RowIndex);
//find location to save it
string savestring = DataGridClass.CellColumn(dataGridView1, "Save_location", e.RowIndex);
//execute export to excel, with the locations saved from above.
GXOMIClassLibrary.My_DataTable_Extensions.ExportToExcelDetailed(returnedDT, loadstring, workbookstring, savestring);
GC.Collect();
GC.WaitForPendingFinalizers();
}
The
GXOMIClassLibrary.My_DataTable_Extensions.ExportToExcelDetailed(returnedDT, loadstring, workbookstring, savestring);
method refers to a class library I have created with this method below;
public static void ExportToExcelDetailed(this System.Data.DataTable DataTable, string ExcelLoadPath, string WorksheetName, string ExcelSavePath)
{
try
{
int ColumnsCount;
//if datatable is empty throw an exception.
if (DataTable == null || (ColumnsCount = DataTable.Columns.Count) == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
//Microsoft.Office.Interop.Excel.Application Excel = new Microsoft.Office.Interop.Excel.Application();
//Excel.Workbooks.Add();
var excelApp = new Excel.Application();
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(ExcelLoadPath);
//TELL THE PROGRAM WHAT WORKBOOK TO OPEN
// select the right worksheet.
var Worksheet = excelWorkbook.Sheets[WorksheetName];
// DataCells
int RowsCount = DataTable.Rows.Count;
object[,] Cells = new object[RowsCount, ColumnsCount];
for (int j = 0; j < RowsCount; j++)
for (int i = 0; i < ColumnsCount; i++)
Cells[j, i] = DataTable.Rows[j][i];
//find last row
var xlRange = (Excel.Range)Worksheet.Cells[Worksheet.Rows.Count, 1];
long lastRow = (long)xlRange.get_End(Excel.XlDirection.xlUp).Row;
long newRow = lastRow + 1;
///cells[2,1] needs to become cell below last paste
Worksheet.Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[newRow, 1]), (Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[newRow + RowsCount -1, ColumnsCount])).Value = Cells;
// check fielpath
if (ExcelSavePath != null && ExcelSavePath != "")
{
try
{
Worksheet.SaveAs(ExcelSavePath);
excelApp.Quit();
// Worksheet.Close(0);
//richTextBox1("Excel file saved!");
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
+ ex.Message);
excelApp.Quit();
}
}
else // no filepath is given
{
excelApp.Visible = true;
}
excelApp.Quit();
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: \n" + ex.Message);
}
}
changing this part of the ExportToExcelDetailed seems to have corrected the issue;
if (ExcelSavePath != null && ExcelSavePath != "")
{
try
{
Worksheet.SaveAs(ExcelSavePath);
excelApp.Quit();
Marshal.ReleaseComObject(Worksheet);
GC.Collect();
GC.WaitForPendingFinalizers();
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
+ ex.Message);
excelApp.Quit();
}
}
else // no filepath is given
{
excelApp.Visible = true;
}
I have an SSRS reports form where in Export my results in Excel file. As Excel behavior is to Enable Protected View for files originating from the internet. it asks for Enable Editing button clicked or setting off for Excel.
i am using script task C# to read excel in SSIS. but to execute it, i need to click on enable editing on in Excel. is there any way to not to set the settings or open the file to make it writable. my script task works in development but fails in deploy mode. below is the code. please help me to figure out.
//pass that to workbook object
Microsoft.Office.Interop.Excel.Workbook workBook = oExcel.Workbooks.Open(workbookPath);
foreach (Worksheet worksheet in workBook.Worksheets)
{
if (worksheet.Name.Equals(sheetName, StringComparison.OrdinalIgnoreCase))
{
Microsoft.Office.Interop.Excel.Range xlRange = worksheet.UsedRange;
object[,] data = new object[xlRange.Rows.Count - 1, xlRange.Columns.Count];
System.Data.DataTable dt = new System.Data.DataTable();
for (int i = 1; i <= xlRange.Rows.Count - 1; i++)
{
for (int j = 1; j <= xlRange.Columns.Count; j++)
{
data[i - 1, j - 1] = (xlRange.Cells[i, j] as Microsoft.Office.Interop.Excel.Range).Value;
}
}
workBook.Close(true);
oExcel.Application.Quit();
oExcel.Quit();
Marshal.ReleaseComObject(workBook);
Marshal.ReleaseComObject(oExcel);
dt = ArraytoDatatable(data);
dt.TableName = tableName;
//BulkLoadDataTable(dt, connectionString);
}
else
{
FireError("Wrong Sheet name found. Please Rename the sheet name as:" + sheetName);
}
}
Dts.TaskResult = (int)ScriptResults.Success;
I have code that converts a .CSV file to a .XLSX file. The conversion goes well, but the WorkBook.SaveAs(#"file.xslx") method seems to only save the file to C:\Users[MyName]\Documents\file.xlsx. When I use Excel.Application.GetSaveAsFileName() it defaults to C:\Users[MyName]\Documents with a Save As dialog.
Furthermore, setting Excel.Application.DefaultFilePath doesn't seem to help unless I explicitly state F:.........
I have a relative working directory set, where a.csv is read from:
using Excel = Microsoft.Office.Interop.Excel;
StreamReader a = new StreamReader(#"a.csv");
var CSVContent = new List<string[]>();
Excel.Application excel = new Excel.Application();
excel.DefaultFilePath = #"Output\"; //doesn't do anything
Excel.Workbook workBook = excel.Workbooks.Add();
Excel.Worksheet sheet = workBook.ActiveSheet;
while (!a.EndOfStream)
{
string read = a.ReadLine();
CSVContent.Add(read.Split(','));
}
for (int i = 0; i < CSVContent.Count; i++) //write List contents to xlsx Line by Line
{
string[] csvLine = CSVContent[i];
for (int j = 0; j < csvLine.Length; j++)
{
sheet.Cells[i + 1, j + 1] = csvLine[j]; //Cells begin at 1 in Excel
}
}
var b = excel.GetSaveAsFilename("a.xlsx");
workBook.SaveAs(b);
workBook.Close();
How do I get workbook.SaveAs() to save into the solution relative working directory?
Relying on relative paths tends to be problematic. If you want to save it to the current directory of the application, use Environment.CurrentDirectory, that is:
var b = Environment.CurrentDirectory + #"\a.xlsx";
In my MVC application I am exporting data to excel using Microsoft.Office.Interop.Excel .
I have also enabled ASP.NET Impersonation and gave the authentication details. It writes data to excel but it doesn't save or opens the excel file. It throws a exception Exception from HRESULT: 0x800A03EC. I will be so glad if anyone could help. thanks in advance.
My code for Export is:
public static void ExportExcel(this DataTable Tbl, string ExcelFilePath = null)
{
ExcelFilePath = "ExportTable.xls";
try
{
if (Tbl == null || Tbl.Columns.Count == 0)
//throw new Exception("ExportToExcel: Null or empty input table!\n");
Console.WriteLine("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
Excel.Application excelApp = new Excel.Application();
excelApp.Workbooks.Add();
// single worksheet
Excel._Worksheet workSheet = excelApp.ActiveSheet;
// column headings
for (int i = 0; i < Tbl.Columns.Count; i++)
{
workSheet.Cells[1, (i + 1)] = Tbl.Columns[i].ColumnName;
workSheet.Cells[1, (i + 1)].Font.Bold = true;
workSheet.Cells[1, (i + 1)].Font.Size = 12;
}
// rows
for (int i = 0; i < Tbl.Rows.Count; i++)
{
// to do: format datetime values before printing
for (int j = 0; j < Tbl.Columns.Count; j++)
{
workSheet.Cells[(i + 2), (j + 1)] = Tbl.Rows[i][j];
}
}
// works fine till here
// check fielpath
if (ExcelFilePath != null && ExcelFilePath != "")
{
try
{
workSheet.SaveAs(ExcelFilePath);
excelApp.Quit();
}
catch (Exception ex)
{
Console.WriteLine("ExportToExcel: Excel file could not be saved! Check filepath.\n"+ ex.Message);
}
}
else // no filepath is given
{
excelApp.Visible = true;
}
}
catch (Exception ex)
{
Console.WriteLine("ExportToExcel: \n" + ex.Message);
}
}
The IIS user account has to have permissions to write the file.
Search for 0x800A03EC in the following article, How to Create Excel file in ASP.NET C#
HRESULT: 0x800A03EC is an unknown (to VB.Net) COM error. This usually happens when Excel throws some error because your input or parameters were wrong. If you try your code in Excel VBA it is often easier to figure out the problem.
I am in the middle of simple method, that saves my DataGridView into an Excel document (1 sheet only) and also adds VBA code and a button to run the VBA code.
public void SaveFile(string filePath)
{
Microsoft.Office.Interop.Excel.ApplicationClass ExcelApp = new Microsoft.Office.Interop.Excel.ApplicationClass();
ExcelApp.Application.Workbooks.Add(Type.Missing);
//Change Workbook-properties.
ExcelApp.Columns.ColumnWidth = 20;
// Storing header part in Excel.
for (int i = 1; i < gridData.Columns.Count + 1; i++)
{
ExcelApp.Cells[1, i] = gridData.Columns[i - 1].HeaderText;
}
//Storing Each row and column value to excel sheet
for (int row = 0; row < gridData.Rows.Count; row++)
{
gridData.Rows[row].Cells[0].Value = "Makro";
for (int column = 0; column < gridData.Columns.Count; column++)
{
ExcelApp.Cells[row + 2, column + 1] = gridData.Rows[row].Cells[column].Value.ToString();
}
}
ExcelApp.ActiveWorkbook.SaveCopyAs(filePath);
ExcelApp.ActiveWorkbook.Saved = true;
ExcelApp.Quit();
}
I only implemented DataGridView export.
EDIT: Thanks to Joel I could, with proper words, search again for the solution. I think that this may be helpful. Would you correct me or give a tip or two about what I should look for.
I just wrote a small example which adds a new button to an existing workbook and afterwards add a macro which will be called when the button is clicked.
using Excel = Microsoft.Office.Interop.Excel;
using VBIDE = Microsoft.Vbe.Interop;
...
private static void excelAddButtonWithVBA()
{
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlBook = xlApp.Workbooks.Open(#"PATH_TO_EXCEL_FILE");
Excel.Worksheet wrkSheet = xlBook.Worksheets[1];
Excel.Range range;
try
{
//set range for insert cell
range = wrkSheet.get_Range("A1:A1");
//insert the dropdown into the cell
Excel.Buttons xlButtons = wrkSheet.Buttons();
Excel.Button xlButton = xlButtons.Add((double)range.Left, (double)range.Top, (double)range.Width, (double)range.Height);
//set the name of the new button
xlButton.Name = "btnDoSomething";
xlButton.Text = "Click me!";
xlButton.OnAction = "btnDoSomething_Click";
buttonMacro(xlButton.Name, xlApp, xlBook, wrkSheet);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
xlApp.Visible = true;
}
And here we got the buttonMacro(..) method
private static void buttonMacro(string buttonName, Excel.Application xlApp, Excel.Workbook wrkBook, Excel.Worksheet wrkSheet)
{
StringBuilder sb;
VBIDE.VBComponent xlModule;
VBIDE.VBProject prj;
prj = wrkBook.VBProject;
sb = new StringBuilder();
// build string with module code
sb.Append("Sub " + buttonName + "_Click()" + "\n");
sb.Append("\t" + "msgbox \"" + buttonName + "\"\n"); // add your custom vba code here
sb.Append("End Sub");
// set an object for the new module to create
xlModule = wrkBook.VBProject.VBComponents.Add(VBIDE.vbext_ComponentType.vbext_ct_StdModule);
// add the macro to the spreadsheet
xlModule.CodeModule.AddFromString(sb.ToString());
}
Found this information within an KB article How To Create an Excel Macro by Using Automation from Visual C# .NET