Export data from DataTable to Excel file - c#

I have DataTable object. How can I export it into an XLS file?
I tried to render it via DataGrid
DataGrid dgGrid = new DataGrid();
dgGrid.DataSource = dt;
dgGrid.DataBind();
dgGrid.RenderControl(hw);
but the file is very large and the OutOfMemoryException appears.
I can use http://epplus.codeplex.com/.
I need C# function.

There are a number of options, one of them being the Access OLE DB Provider which also operates in terms of DataTables.
If you want more fine-grained support over the document, I'd recommend the Open XML SDK 2.0, whixh is .xmlx only.
For raw data, I think that Access OLE DB (also reffered to as the ACE provider) is the best choice since it enables a database-like experience. Open XML assumes fairly good knowledge of XML and the willingnes to experiment a bit more. On the other hand, you can apply formatting, add formulas and other advanced features.

Ok, find a solution here: http://bytesofcode.hubpages.com/hub/Export-DataSet-and-DataTable-to-Excel-2007-in-C
Just download epplus library and call method:
private void GenerateExcel(DataTable dataToExcel, string excelSheetName)
{
string fileName = "ByteOfCode";
string currentDirectorypath = Environment.CurrentDirectory;
string finalFileNameWithPath = string.Empty;
fileName = string.Format("{0}_{1}", fileName, DateTime.Now.ToString("dd-MM-yyyy"));
finalFileNameWithPath = string.Format("{0}\\{1}.xlsx", currentDirectorypath, fileName);
//Delete existing file with same file name.
if (File.Exists(finalFileNameWithPath))
File.Delete(finalFileNameWithPath);
var newFile = new FileInfo(finalFileNameWithPath);
//Step 1 : Create object of ExcelPackage class and pass file path to constructor.
using (var package = new ExcelPackage(newFile))
{
//Step 2 : Add a new worksheet to ExcelPackage object and give a suitable name
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(excelSheetName);
//Step 3 : Start loading datatable form A1 cell of worksheet.
worksheet.Cells["A1"].LoadFromDataTable(dataToExcel, true, TableStyles.None);
//Step 4 : (Optional) Set the file properties like title, author and subject
package.Workbook.Properties.Title = #"This code is part of tutorials available at http://bytesofcode.hubpages.com";
package.Workbook.Properties.Author = "Bytes Of Code";
package.Workbook.Properties.Subject = #"Register here for more http://hubpages.com/_bytes/user/new/";
//Step 5 : Save all changes to ExcelPackage object which will create Excel 2007 file.
package.Save();
MessageBox.Show(string.Format("File name '{0}' generated successfully.", fileName)
, "File generated successfully!", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

First of all, Google is your best friend. Also you can search on this site.
Some solutions:
You can write an excel file with SQL.
You can use the reference to Microsoft Office library to create an excel file
You can write an XML file.

Related

How to Auto Fit Excel Columns in MVC-4 ActionResult before returning EXCEL File?

Following is the ActionResult Method created to return EXCEl File, which works fine. However, there is a problem that the content for each column is too large that the rows are mal-formed, which means there are wide blank-spaces between rows.
Following is the ActionResult code.
public ActionResult ImportExecelFile(int appNo)
{
List<PendingApproval> pendings = objPA.GetPendingApprovals(appNo.ToString());
string xml = String.Empty;
XmlDocument xmlDoc = new XmlDocument();
XmlSerializer xmlSerializer = new XmlSerializer(pendings.GetType());
using (MemoryStream xmlStream = new MemoryStream())
{
xmlSerializer.Serialize(xmlStream, pendings);
xmlStream.Position = 0;
xmlDoc.Load(xmlStream);
xml = xmlDoc.InnerXml;
}
//Create file
string fileName = "Pending_Approvals";
fileName += string.Format("-{0}", DateTime.Now.ToString("yyyy-MM-dd"));
fileName += ".xls";
byte[] fileContents = Encoding.UTF8.GetBytes(xml);
return File(fileContents, "application/vnd.ms-excel", fileName);
}
You're not creating an Excel file - you're creating XML and saving it with an .xls extension. Excel will try its best to open it, although it's probably going to raise a warning to the user because it's not really an Excel file.
Excel files can contain formatting, including column widths. Data serialized as XML will not have that. So there's really no way to control how Excel displays the XML.
You can accomplish what you're trying to do using a library like EPPlus that creates Excel workbooks using OpenXML. But if you're just saving XML as .xls then you won't have any control over formatting. (I'm amazed it opens at all, but I tested saving an XML file as .xls and it worked except for the warning message.)

.xlsx Created and Saved Using Template with EPPlus is Unreadable/Corrupt

The Problem
I'm trying to create a small program that uses an Excel template to create an Excel document and then writes to several cells using EPPlus. Unfortunately, the files appear to be corrupt no matter what I try.
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OfficeOpenXml;
using System.IO;
namespace ConsoleApplication9
{
public sealed class ExcelSerialize
{
private readonly List<Tuple<string, string>> Results;
private readonly string Directory;
private ExcelPackage package;
public ExcelSerialize(List<Tuple<string, string>> Results, string Directory)
{
this.Results = Results;
this.Directory = Directory;
}
public bool WriteResults()
{
FileInfo template = new FileInfo(Directory);
using (package = new ExcelPackage(template, true))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
//foreach (Tuple<string, string> Result in Results)
//{
// worksheet.Cells[Result.Item1].Value = Result.Item2;
//}
string file = string.Format(System.AppDomain.CurrentDomain.BaseDirectory.ToString() + #"results\results" + System.DateTime.Now.ToString().Replace(" ", "").Replace("/", "_").Replace(":", "-") + ".xlsx");
Byte[] bin = package.GetAsByteArray();
File.WriteAllBytes(file, bin);
return true;
}
}
}
}
Things I've tried:
Changing the values of various cells in the template.
Saving an Excel document created from the template without writing any new data to it.
Creating a basic template with the cells A1, A2, and A3 containing "TEST" and no other edits instead of the more complicated template I intend to use.
Saving using Package.SaveAs().
Saving using the Byte array seen in the example code.
Compiling EPPlus from the latest source provided on Codeplex.
Things that work:
Creating a new file using the following code:
using (package = new ExcelPackage(string.Format(System.AppDomain.CurrentDomain.BaseDirectory.ToString() + #"results\results" + System.DateTime.Now.ToString().Replace(" ", "").Replace("/", "_").Replace(":", "-") + ".xlsx"))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Test");
worksheet.Cells[A1].Value = "Test";
package.Save();
}
Notes:
For whatever reason, the files saved still appear corrupt and can't be recovered. I'm currently using Microsoft Office 2010. The file formats I'm using are .xltx and .xlsx.
Short Answer:
The EPPlus library does not support creation of a file from an existing xltx Excel template.
Use a pre-formatted xlsx file instead.
Long Answer:
Dim excelFile As New FileInfo(filename)
Dim reportTemplate As New FileInfo(templatePath)
Dim xlFile As ExcelPackage = New ExcelPackage(excelFile, reportTemplate)
' Do Stuff
xlFile.Save()
When instantiating a new ExcelPackage object using EPPlus you're supposed to be able to provide a template as the second parameter (see code snippet above), however when providing it with an xltx file I kept getting a corrupt output file same as the user above. I eventually found that supplying a regular xlsx file as the template, rather than an actual template file, appeared to work.
This is an open source package, so I decided to take a quick look at the source.
It looks like the ExcelPackage constructors that accept the "template" parameter, call the CreateFromTemplate() method. The comments on the CreateFromTemplate() method states that it expects an existing xlsx file to use as a template, not an actual template file.
So while one might assume that the 'template' parameter refers to an actual xltx template file, it appears that EPPlus does not support that.
Similar problem faced, this worked by just giving me back the template
public ExcelPackage getSheet(string templatePath){
FileInfo template = new FileInfo(templatePath);
ExcelPackage p = new ExcelPackage(template, true);
ExcelWorksheet ws = p.Workbook.Worksheets[1]; //position of the worksheet
ws.Name = bookName;
p.Save();
ExcelPackage pck = new ExcelPackage(new System.IO.MemoryStream(), p.Stream);
return pck;
Then you call with this
string path = Server.MapPath(#"../../../Ex/template.xlsx")
try
{
OfficeOpenXml.ExcelPackage pck = getSheet(path);
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", String.Format(System.Globalization.CultureInfo.InvariantCulture, "attachment; filename={0}", fileName + ".xlsx"));
Response.BinaryWrite(pck.GetAsByteArray());
Response.End();
}
catch { }
Explicitly close the File after you write the data to it.
I know when you use EPPlus in a response on a web request closing the response removes that issue.

Find and replace value in Excel using C#

How can I find some value from cell and replace by new value in Excel?
I tryed this but it doesn't works:
Microsoft.Office.Interop.Excel.Application xlapp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wb =default(Microsoft.Office.Interop.Excel.Workbook);
wb = xlapp.Workbooks.Open(FileName.ToString());
wb.Worksheets[0].Cells.Replace("find","replace");
I would recommend you use NPOI which can be accessed either via codeplex or directly through Nuget in Visual Studio. It gives you the ability to easily upload, edit and create spreadsheets in .NET
Example of uploading a spreadsheet:
HSSFWorkbook hssfworkbook;
void InitializeWorkbook(string path)
{
//read the template via FileStream, it is suggested to use FileAccess.Read to prevent file lock.
//book1.xls is an Excel-2007-generated file, so some new unknown BIFF records are added.
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
{
hssfworkbook = new HSSFWorkbook(file);
}
}
You can then use the IRow and ICell collections of the spreadsheet to locate and edit the data you need before doing an export.
More examples can be found here
If interested, you can use GemBox.Spreadsheet for this, like so:
SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
// Load your XLS, XLSX, ODS or CSV file.
ExcelFile wb = ExcelFile.Load(FileName.ToString());
ExcelWorksheet ws = wb.Worksheets[0];
// Replace all "find" occurances with "replace" text.
int row, column;
while(ws.Cells.FindText("find", out row, out column))
ws.Cells[row, column].ReplaceText("find", "replace");
// Save your XLS, XLSX, ODS or CSV file.
wb.Save(FileName.ToString());
Also you can find another searching in Excel example here.
All you have to do is replace
wb.Worksheets[0].Cells.Replace("find","replace");
with
wb.Worksheets[1].Cells.Replace("find","replace");

Convert datatable to excel 2007(.xlsx)

I have an DataTable I need to put into Excel 2007 format and save it as an excel file(.xlsx) 2007.
Can anyone help me to achieve this?
You can use an OLEDB data provider and just treat Excel as another ADO.NET data source in order to loop through your DataTable rows and insert them into the Excel spreadsheet. Here's a Microsoft KB article that walks you through a lot of the details.
http://support.microsoft.com/kb/316934/en-us
The big thing to keep in mind is that you can create workbooks and sheets within the workbook, and you can reference existing sheets by appending a '$' at the end of the name. If you omit the '$' at the end of the sheet name, the OLEDB provider will assume that it's a new sheet and will try to create it.
The dollar sign following the
worksheet name is an indication that
the table exists. If you are creating
a new table, as discussed in the
Create New Workbooks and Tables
section of this article, do not use
the dollar sign.
You can create and spreadsheet in 2003 (.xls) or 2007 format (xlsx), and that's defined on your connection string -- you specify the file that you're going to write to, and just specify the extension. Make sure you use the right OLEDB provider version.
If you want to create a 2003 (.xls) version, you use this connection string:
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Book1.xls;Extended Properties="Excel 8.0;HDR=YES
If you want to create a 2007 (.xlsx) version, you use this connection string:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Book1.xlsx;Extended Properties="Excel 12.0;HDR=YES
You may have to download the ACE provider from Microsoft in order to create XLSX files. You can find it here.
I usually use the XLS provider, so I haven't worked with the XLSX provider as much.
Hope this helps. Let me know if you have other questions.
I wrote the following code for the company some time back. It takes Enumerable of any class type and exports all its (get)properties to Excel and also open Excel. You should be able to do something similar for a DataTable. Remember you need to add reference to Microsoft.Office.Interop.Excel
public static void ExportToExcel<T>(IEnumerable<T> exportData)
{
Excel.ApplicationClass excel = new Excel.ApplicationClass();
Excel.Workbook workbook = excel.Application.Workbooks.Add(true);
PropertyInfo[] pInfos = typeof(T).GetProperties();
if (pInfos != null && pInfos.Count() > 0)
{
int iCol = 0;
int iRow = 0;
foreach (PropertyInfo eachPInfo in pInfos.Where(W => W.CanRead == true))
{
// Add column headings...
iCol++;
excel.Cells[1, iCol] = eachPInfo.Name;
}
foreach (T item in exportData)
{
iRow++;
// add each row's cell data...
iCol = 0;
foreach (PropertyInfo eachPInfo in pInfos.Where(W => W.CanRead == true))
{
iCol++;
excel.Cells[iRow + 1, iCol] = eachPInfo.GetValue(item, null);
}
}
// Global missing reference for objects we are not defining...
object missing = System.Reflection.Missing.Value;
// If wanting to Save the workbook...
string filePath = System.IO.Path.GetTempPath() + DateTime.Now.Ticks.ToString() + ".xlsm";
workbook.SaveAs(filePath, Excel.XlFileFormat.xlOpenXMLWorkbookMacroEnabled, missing, missing, false, false, Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
// If wanting to make Excel visible and activate the worksheet...
excel.Visible = true;
Excel.Worksheet worksheet = (Excel.Worksheet)excel.ActiveSheet;
excel.Rows.EntireRow.AutoFit();
excel.Columns.EntireColumn.AutoFit();
((Excel._Worksheet)worksheet).Activate();
}
}
I have an DataTable I need to put into Excel 2007 format and save it
as an excel file(.xlsx) 2007.
Can anyone help me to achieve this?
You just need to add my free C# class to your project, and one line of code.
Full details (with free downloadable source code, and an example project) here:
Mikes Knowledge Base - Export to Excel
My library uses the free Microsoft OpenXML libraries (also provided in my downloads) to write the file, so you don't have to use the heavyweight VSTO libraries, or have Excel installed on your server.
Also, it creates a real .xlsx file, rather than some other methods which write a stream of data to a comma-separated text file, but name it as a .xls file.
By the way, I had loads of difficulties writing to Excel files using OLEDB, not least because I was running Windows 7 64-bit, with Office 2007 (which is 32-bit) and the Microsoft ACE provider has to be the 64-bit edition... but you can't install this, if you have the 32-bit version of Office installed.
So, you have to uninstall Office, install the ACE driver, and then re-install Office.
But even then, I gave up using OLEDB.. it just wasn't stable enough.
Found this in some old code I did like 5 years ago that should work...
public static void DataTableToExcel(DataTable tbl)
{
HttpContext context = HttpContext.Current;
context.Response.Clear();
foreach (DataColumn c in tbl.Columns)
{
context.Response.Write(c.ColumnName + ";");
}
context.Response.Write(Environment.NewLine);
foreach (DataRow r in tbl.Rows)
{
for (int i = 0; i < tbl.Columns.Count; i++)
{
context.Response.Write(r[i].ToString().Replace(";", string.Empty) + ";");
}
context.Response.Write(Environment.NewLine);
}
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition",
"attachment; filename=export.csv");
context.Response.End();
}
This will output from ASP.NET a response with a CSV file that Excel 2007 can open. If you want you can change the extension to mimic excel and it should work just by replacing the following lines:
context.Response.ContentType = "application/vnd.ms-excel";
context.Response.AppendHeader("Content-Disposition",
"attachment; filename=export.xlsx");
A CSV is the easiest way if you don't need to do anything complex. If you do require it to truly be a Excel 2007 file in the native format, you will need to use an Office library to build it or convert it from the CSV and then serve/save it.
This link might also be useful:
How to avoid the Excel prompt window when exporting data to Excel 2007
Saw that someone else posted a "save to csv" option. While that didn't seem to be the answer the OP was looking for, here is my version that includes the table's headers
public static String ToCsv(DataTable dt, bool addHeaders)
{
var sb = new StringBuilder();
//Add Header Header
if (addHeaders)
{
for (var x = 0; x < dt.Columns.Count; x++)
{
if (x != 0) sb.Append(",");
sb.Append(dt.Columns[x].ColumnName);
}
sb.AppendLine();
}
//Add Rows
foreach (DataRow row in dt.Rows)
{
for (var x = 0; x < dt.Columns.Count; x++)
{
if (x != 0) sb.Append(",");
sb.Append(row[dt.Columns[x]]);
}
sb.AppendLine();
}
return sb.ToString();
}

Creating cell comments in an Excel Spreadsheet with OpenXML SDK

I'm trying to add comments to cells in an Excel 2007 spreadsheet. I'm using the OpenXml SDK 2.0 to do so.
My use case is this:
I've created a template Excel file that I copy and use that as my starting point, rather than create an OpenXML document from scratch. My template file has a comment in cell A1 so that Excel has already created a WorksheetCommentPart for me.
Now my problem is that when I add Comment nodes to the Comments part the spreadsheet doesn't load and Excel asks if I want to recover.
What really bothers me is that my original comment in A1 is still there, but any comments I added programmatically are gone!
Here's the code I'm working with:
using (MemoryStream spreadsheetStream = new MemoryStream())
{
GetGradebookSpreadsheetTemplate(spreadsheetStream);
using (SpreadsheetDocument spDoc = SpreadsheetDocument.Open(spreadsheetStream, true))
{
WorkbookPart wbPart = spDoc.WorkbookPart;
WorksheetPart wsPart = wbPart.WorksheetParts.First();
SheetData sheet = wsPart.Worksheet.GetFirstChild<SheetData>();
Comments comments = wsPart.WorksheetCommentsPart.Comments;
comments.Descendants<Author>().First().Text = string.Format("{0}, {1}", instructor.LastName, instructor.FirstName);
comments.Descendants<Text>().First().Text = string.Format("{0}, {1}", instructor.LastName, instructor.FirstName);
List<DefinedName> definedNames = new List<DefinedName>();
definedNames.Add(CreateDefinedName("COLWeb_Gradebook", sheet.NamespaceURI, "Gradebook", "1", "A"));
uint index = 4;
foreach (User u in users)
CreateUserDataRow(index++, definedNames, comments.CommentList, sheet, u, coursesForUsers[u], assignments, submissions[u]);
Cell lastCell = sheet.Descendants<Cell>().Last();
OpenXmlElement dimensionsElement = wsPart.Worksheet.Elements().Where(x => x.LocalName == "dimension").First();
dimensionsElement.SetAttribute(new OpenXmlAttribute("ref", null, "A1:" + lastCell.CellReference));
comments.Save();
wsPart.Worksheet.Save();
wbPart.Workbook.Save();
}
return spreadsheetStream.ToArray();
}
And "CreateUserDataRow" creates a new row, but the relevant part is (where "comment" is my comment string and "c" is my Cell that I want to create the comment about):
if (!string.IsNullOrEmpty(comment))
{
List<OpenXmlElement> runs = new List<OpenXmlElement>();
foreach (string row in comment.Split(new string[] { "<p>", "</p>" }, StringSplitOptions.RemoveEmptyEntries))
{
string trimmed = row.Trim();
if (!string.IsNullOrEmpty(trimmed))
{
string escaped = System.Security.SecurityElement.Escape(trimmed);
runs.Add(new Run(new RunProperties(), new Text(escaped)));
}
}
Comment commentCell = new Comment();
commentCell.Reference = c.CellReference;
commentCell.AuthorId = 0;
commentCell.AppendChild(new CommentText(runs));
comments.AppendChild(commentCell);
}
Now as far as my eye can see, and KDiff3 for that matter, my files are pretty much identical to the files that would be output if I were to open Excel and put the comments into the cells by hand in Excel.
Does anyone have a good example of attaching a comment to a cell with OpenXml? Is there something I should know about maybe a relationship? Does it have something to do with using an Excel file that I created and then I'm using as a template (maybe some dimensions aren't set)?
Thanks for any help I can get.
Unfortunately, it is not that simple.
Cell comments also have a graphics object which is in a VML drawing part. VML is a cryptic legacy specification and is not in the approved ECMA standard. You can find documentation on it in Microsoft's Open XML documents, but it is not pretty. Hopefully Microsoft will address this in Excel 14 by adding full cell comment support as well as support for controls which are also written to VML.
Having said that, I have not used the Open XML SDK and I cannot say whether or not it is possible to add comments with it. I just thought this might help get you pointed in the right direction.
There appears to be a code sample at http://openxmldeveloper.org/forums/thread/7396.aspx which shows how to create the requisite VML Drawing. I'm trying this code now, and seem to have progressed, though I'm still getting some sort of unspecified error in which Excel decides to drop the comments before opening...

Categories