I have a datatable with larger than 300.000 row, i want export this datatable to excel 2003 but don't use Excel COM. I have used NPOI but it raise error OutOfMemory. I'm finding a thirt party component (free) can export for each row and write directly to file to avoid out of memory. Who can help me? thanks.
How about a csv file ? It is readable from Excel.
Try this Libs. I am not sure about the capacity
http://ehl.codeplex.com/
http://excelexportlib.codeplex.com/
You can export to an excel-file with the use of a webgrid (only in code). Under the assumption that you're creating a WinForm-application, you will have to make a reference to the System.Web library.
// Create the DataGrid and perform the databinding
var myDataGrid = new System.Web.UI.WebControls.DataGrid();
myDataGrid.HeaderStyle.Font.Bold = true;
myDataGrid.DataSource = myDataTable;
myDataGrid.DataBind();
string myFile = "put the name here with full path.xls"
var myFileStream = new FileStream( myFile, FileMode.Create, FileAccess.ReadWrite );
// Render the DataGrid control to a file
using ( var myStreamWriter = new StreamWriter( myFileStream ) )
{
using (var myHtmlTextWriter = new System.Web.UI.HtmlTextWriter(myStreamWriter ))
{
myDataGrid .RenderControl( myHtmlTextWriter );
}
}
I haven't tested it with so many records, so I don't know the impact of this memory-wise.
Edit:
Take note of the comment of #Charles Williams that excel 2003 has a row limitation
Related
I am trying to use OpenXML to programmatically set an Excel workbook to visible, but am fairly new to C# and am not sure how to do that.
We are using a 3rd party application that stores Office documents and I'm tasked with reporting. One of the many strange things it does is compresses documents before saving them and sets Excel Workbook visibility to false in the database record.
According to the documentation there is the function that should do that:
public DocumentFormat.OpenXml.EnumValue<DocumentFormat.OpenXml.Spreadsheet.VisibilityValues> Visibility { get; set; }
How do I translate that into a working C# example? I don't have much so far:
using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray, 0, (int)byteArray.Length);
using (SpreadsheetDocument rptTemplate = SpreadsheetDocument.Open(mem, true))
{ // the next line doesn't work
rptTemplate.WorkbookPart.Workbook.WorkbookProperties.SetAttribute(VisibilityValues = visible)
rptTemplate.WorkbookPart.Workbook.Save();
rptTemplate.SaveAs(filePathName);
}
}
first of all you need to get WorkbookView of your workbook, so
var workBookView = workbookpart.Workbook.Descendants<WorkbookView>().FirstOrDefault();
and then you can set desired visibility :
workBookView.Visibility = VisibilityValues.Hidden;
if you are creating spreadsheet document you should create workBookView before you can use it,like below:
spreadsheetDocument.WorkbookPart.Workbook.Append(new BookViews(new WorkbookView()));
I am exporting a data table to Excel using EPPlus but I keep getting no results. I get a worksheet with headers and a label on the tab but no data. I verified that the tableadapter has data in it.
Here is my code:
FileInfo newFile = new FileInfo("c:\temp\fn.xlsx");
ExcelPackage epp = new ExcelPackage(newFile);
var ws = epp.Workbook.Worksheets.Add(acctno);
TransTableAdapter.FillByAcct(MSDataSet.TransWithName, acctno);
ws.Cells.LoadFromDataTable(MSDataSet.TransWithName, true, OfficeOpenXml.Table.TableStyles.Light8);
epp.Save();
epp.Dispose();
Please kindly help if you can. Thanks!
In case anyone else runs into this problem, here is the solution -- use GET and not FILL:
MSDataSet.TransDataTable newTransTable;
newTransTable = TransTableAdapter.GetDataByDFI(#acctno);
ws.Cells.LoadFromDataTable(newTransTable, true, OfficeOpenXml.Table.TableStyles.Light8);
I want to use EPPlus to input data and calculate it.
Here is my code:
ExcelWorksheet sheet = ep.Workbook.Worksheets["input"];
sheet.Cells[1, 1].Value = 10;
ep.Workbook.Calculate();
string test = sheet.Cells[1, 5].Text;
ep.Save();
The string test is "#NAME?"
It seems that EPPlus did not load user define function.
When I open the saved file, the calculation will be done automatically.
What should I do to make the user defined function work?
(I'll use this feature later in the ASP.NET to call User define functions in exist excel file.I tried Interop, it can achieve what I want, but a lot slower.)
Thanks!
The formula calc engine in EPPlus cannot execute VBA functions in the workbook. It supports approx. 150 common built in Excel formulas and nothing more than that.
However, you can implement your VBA functions in .NET code. Each function should inherit the EPPlus class ExcelFunction and be registred to EPPlus via the Workbook.FormulaParserManager given the same function name as your VBA functions.
There are samples that illustrates this (create custom functions) in the EPPlus Samples project which can be downloaded from Codeplex.
For version 4.1, you can download the solution "EPPlus with samples" here:
https://epplus.codeplex.com/releases/view/625020
Then goto the "EPPlusSamples" project and check out SampleAddFormulaFunction.cs
You need to create a vba project in Epplus which is where you would define the function. Something like this:
var fileinfo = new FileInfo(#"c:\temp\UserDefinedFunctionTest.xlsm");
if (fileinfo.Exists)
fileinfo.Delete();
var sb = new StringBuilder();
sb.AppendLine("Function test(a)");
sb.AppendLine(" test = a * 3");
sb.AppendLine("End Function");
using (var package = new ExcelPackage(fileinfo))
{
var workbook = package.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
workbook.CreateVBAProject();
var mod1 = workbook.VbaProject.Modules.AddModule("Module1");
mod1.Code = sb.ToString();
worksheet.Cells["A1"].Value = 5;
worksheet.Cells["A2"].Formula = "=test(A1)";
package.Save();
}
Which will look like this:
You need to set formula in ExcelWorkSheet
sheet.Cells[5, 5].Formula = "=A1*3";
This is for first row only , if you want to do in Large number of rows then you have to use loop and inside loop use formula.
I have a C# data processing application which uses EPPlus to write the final results into an excel sheet. The background color of the rows are changed based on what the data on that row signifies. Time was never an issue as I only dealt with files that were below <100MB before. However, as my requirements have changed and the files get larger, I have noticed that.. just coloring makes my application 60% slower. Removing coloring makes the application significantly faster. The snippet below is an example of the code which I use to color the data to make it visually distinguishing. I'm no expert at EPPlus but is there a way, this can be optimized to make my application faster? Or are there any better ways for me to make the rows visually distinct for the people who will end up looking at the data? Any help will be appreciated!
if (data[4] == "3")
{
// color the type 3 messages here
var fill1 = cell1.Style.Fill;
fill1.PatternType = ExcelFillStyle.Solid;
fill1.BackgroundColor.SetColor(Color.LightGray);
}
if (data[4] == "4")
{
var fill1 = cell1.Style.Fill;
fill1.PatternType = ExcelFillStyle.Solid;
fill1.BackgroundColor.SetColor(Color.BlanchedAlmond);
}
EDIT:
This is the code I use to copy the template and write the excel data into the new worksheet. p is an Excel Package which I convert to a byte Array before writing to the excel file.
Byte[] bin = p.GetAsByteArray();
File.Copy("C:\\Users\\mpas\\Desktop\\template.xlsx", "C:\\Users\\mpas\\Desktop\\result.xlsx");
using (FileStream fs = File.OpenWrite("C:\\Users\\mpas\\Desktop\\result.xlsx")) {
fs.Write(bin, 0, bin.Length);
}
Styling is much faster in EPPlus, and most Excel APIs, if you use named styles. Assign and use the style to cell in EPPlus like this ...
internal static string YourStyleName = "MyStyle";
ExcelNamedStyleXml yourStyle = excel.Workbook.Styles.CreateNamedStyle(YourStyleName);
yourStyle.Style.Font.Color.SetColor(Color.DarkRed);
yourStyle.Style.Fill.PatternType = ExcelFillStyle.Solid;
yourStyle.Style.Fill.BackgroundColor.SetColor(Color.LemonChiffon);
// ...
sheet.Cells[sourceRange].StyleName = YourStyleStyleName
Here is code to open an existing file.
FileInfo AddressList = new FileInfo("c:\test\test.xlsx");
// Open and read the XlSX file.
try
{
using (ExcelPackage package = new ExcelPackage(AddressList))
{
// Get the work book in the file
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
// Get the first worksheet
//ExcelWorksheet Worksheet = workBook.Worksheets.First();
var worksheet = package.Workbook.Worksheets[1];
I can successfully inject a piece of VBA code into a generated excel workbook, but what I am trying to do is use the Workbook_Open() event so the VBA code executes when the file opens. I am adding the sub to the "ThisWorkbook" object in my xlsm template file. I then use the openxml productivity tool to reflect the code and get the encoded VBA data.
When the file is generated and I view the VBA, I see "ThisWorkbook" and "ThisWorkbook1" objects. My VBA is in "ThisWorkbook" object but the code never executes on open. If I move my VBA code to "ThisWorkbook1" and re-open the file, it works fine. Why is an extra "ThisWorkbook" created? Is it not possible to inject an excel spreadsheet with a Workbook_Open() sub? Here is a snippet of the C# code I am using:
private string partData = "..."; //base 64 encoded data from reflection code
//open workbook, myWorkbook
VbaProjectPart newPart = myWorkbook.WorkbookPart.AddNewPart<VbaProjectPart>("rId1");
System.IO.Stream data = GetBinaryDataStream(partData);
newPart.FeedData(data);
data.Close();
//save and close workbook
Anyone have ideas?
Based on my research there isn't a way to insert the project part data in a format that you can manipulate in C#. In the OpenXML format, the VBA project is still stored in a binary format. However, copying the VbaProjectPart from one Excel document into another should work. As a result, you'd have to determine what you wanted the project part to say in advance.
If you are OK with this, then you can add the following code to a template Excel file in the 'ThisWorkbook' Microsoft Excel Object, along with the appropriate Macro code:
Private Sub Workbook_Open()
Run "Module1.SomeMacroName()"
End Sub
To copy the VbaProjectPart object from one file to the other, you would use code like this:
public static void InsertVbaPart()
{
using(SpreadsheetDocument ssDoc = SpreadsheetDocument.Open("file1.xlsm", false))
{
WorkbookPart wbPart = ssDoc.WorkbookPart;
MemoryStream ms;
CopyStream(ssDoc.WorkbookPart.VbaProjectPart.GetStream(), ms);
using(SpreadsheetDocument ssDoc2 = SpreadsheetDocument.Open("file2.xlsm", true))
{
Stream stream = ssDoc2.WorkbookPart.VbaProjectPart.GetStream();
ms.WriteTo(stream);
}
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[short.MaxValue + 1];
while (true)
{
int read = input.Read(buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write(buffer, 0, read);
}
}
Hope that helps.
I found that the other answers still resulted in the duplicate "Worksheet" object. I used a similar solution to what #ZlotaMoneta said, but with a different syntax found here:
List<VbaProjectPart> newParts = new List<VbaProjectPart>();
using (var originalDocument = SpreadsheetDocument.Open("file1.xlsm"), false))
{
newParts = originalDocument.WorkbookPart.GetPartsOfType<VbaProjectPart>().ToList();
using (var document = SpreadsheetDocument.Open("file2.xlsm", true))
{
document.WorkbookPart.DeleteParts(document.WorkbookPart.GetPartsOfType<VbaProjectPart>());
foreach (var part in newParts)
{
VbaProjectPart vbaProjectPart = document.WorkbookPart.AddNewPart<VbaProjectPart>();
using (Stream data = part.GetStream())
{
vbaProjectPart.FeedData(data);
}
}
//Note this prevents the duplicate worksheet issue
spreadsheetDocument.WorkbookPart.Workbook.WorkbookProperties.CodeName = "ThisWorkbook";
}
}
You need to specify "codeName" attribute in the "xl/workbook..xml" object
After feeding the VbaProjectPart with macro. Add this code:
var workbookPr = spreadsheetDocument.WorkbookPart.Workbook.Descendants<WorkbookProperties>().FirstOrDefault();
workbookPr.CodeName = "ThisWorkBook";
After opening the file everything should work now.
So, to add macro you need to:
Change document type to macro enabled
Add VbaProjectPart and feed it with earlier created macro
Add workbookPr codeName attr in xl/workbook..xml with value "ThisWorkBook"
Save as with .xlsm ext.