using .net 4.5
I'm trying to read .xls/.xlsx file using EPPlus (v4.0.4), but get an error. SO has questions on the same error but none relate or solve my problem.
protected void Page_Load(object sender, EventArgs e)
{
GetDataTableFromExcel(#"D:\test.xlsx");
}
private DataTable GetDataTableFromExcel(string path, bool hasHeader = true)
{
using (var pck = new OfficeOpenXml.ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
var ws = pck.Workbook.Worksheets[1];
DataTable tbl = new DataTable();
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
return tbl;
}
}
The error occurs at pck.Load(stream);
A disk error occurred during a write operation. (Exception from
HRESULT: 0x8003001D (STG_E_WRITEFAULT)
A simple example how you can use EPPlus to read excel file:
Reff : http://sforsuresh.in/reading-excel-file-using-epplus-package/
public void readXLS(string FilePath)
{
FileInfo existingFile = new FileInfo(FilePath);
using (ExcelPackage package = new ExcelPackage(existingFile))
{
//get the first worksheet in the workbook
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int colCount = worksheet.Dimension.End.Column; //get Column Count
int rowCount = worksheet.Dimension.End.Row; //get row count
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
Console.WriteLine(" Row:" + row + " column:" + col + " Value:" + worksheet.Cells[row, col].Value.ToString().Trim());
}
}
}
}
We can first convert the xls file to xlsx format using Microsoft.Office.Introp.excel, AFTER the conversion use new formatted file to read with EPPPLUS.
public static DataTable ReadExcelFileToDataTable(string filePath, bool isFirstRowHeader = true)
{
#region Convert xls file to xlsx file
// Convert xls file to xlsx file --to use below code Microsoft.Excel must installed on the system on which cod eis running
var app = new Microsoft.Office.Interop.Excel.Application();
var web = app.Workbooks.Open("");
web.SaveAs(filePath + ".x", FileFormat: Microsoft.Office.Interop.Excel.XlFileFormat.xlOpenXMLWorkbook);
web.Close();
app.Quit();
#endregion
var newFileName = filePath + ".x";
DataTable tbl = new DataTable(); ;
Excel.ExcelPackage xlsPackage = new Excel.ExcelPackage(new FileInfo(newFileName)); //using Excel = OfficeOpenXml; <--EPPLUS
Excel.ExcelWorkbook workBook = xlsPackage.Workbook;
try
{
Excel.ExcelWorksheet wsworkSheet = workBook.Worksheets[0];
foreach (var firstRowCell in wsworkSheet.Cells[1, 1, 1, wsworkSheet.Dimension.End.Column])
{
var colName = "";
colName = firstRowCell.Text;
tbl.Columns.Add(isFirstRowHeader ? colName : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = isFirstRowHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= wsworkSheet.Dimension.End.Row; rowNum++)
{
var wsRow = wsworkSheet.Cells[rowNum, 1, rowNum, wsworkSheet.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return tbl;
}
With this code you won't get an error because a cell is null. it will also cast the data type according to the properties in your class!
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using OfficeOpenXml;
public static class ReadExcel
{
public static List<T> ReadExcelToList<T>(this ExcelWorksheet worksheet) where T : new()
{
List<T> collection = new List<T>();
try
{
DataTable dt = new DataTable();
foreach (var firstRowCell in new T().GetType().GetProperties().ToList())
{
//Add table colums with properties of T
dt.Columns.Add(firstRowCell.Name);
}
for (int rowNum = 2; rowNum <= worksheet.Dimension.End.Row; rowNum++)
{
var wsRow = worksheet.Cells[rowNum, 1, rowNum, worksheet.Dimension.End.Column];
DataRow row = dt.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
//Get the colums of table
var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName).ToList();
//Get the properties of T
List<PropertyInfo> properties = new T().GetType().GetProperties().ToList();
collection = dt.AsEnumerable().Select(row =>
{
T item = Activator.CreateInstance<T>();
foreach (var pro in properties)
{
if (columnNames.Contains(pro.Name) || columnNames.Contains(pro.Name.ToUpper()))
{
PropertyInfo pI = item.GetType().GetProperty(pro.Name);
pro.SetValue(item, (row[pro.Name] == DBNull.Value) ? null : Convert.ChangeType(row[pro.Name], (Nullable.GetUnderlyingType(pI.PropertyType) == null) ? pI.PropertyType : Type.GetType(pI.PropertyType.GenericTypeArguments[0].FullName)));
}
}
return item;
}).ToList();
}
catch (Exception ex)
{
//Save error log
}
return collection;
}
}
How to call this function? please view below code.
public List<Users> GetStudentsFromExcel(HttpPostedFileBase file)
{
List<Users> list = new List<Users>();
if (file != null)
{
try
{
using (ExcelPackage package = new ExcelPackage(file.InputStream))
{
ExcelWorkbook workbook = package.Workbook;
if (workbook != null)
{
ExcelWorksheet worksheet = workbook.Worksheets.FirstOrDefault();
if (worksheet != null)
{
list = worksheet.ReadExcelToList<Users>();
//Your code
}
}
}
}
catch (Exception ex)
{
//Save error log
}
}
return list;
}
public class Users
{
public string Code { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public DateTime CreatedAt { get; set; }
}
Hope to help someone!
Related
I have a requirement where-in I have to fill dataTable from a sheet of Microsoft excel.
The sheet may have lots of data so the requirement is that when a foreach loop is iterated over the data table which is supposed to hold the data from Microsoft excel sheet should fill the table on demand.
Meaning if there are 1000000 records in the sheet the data table should fetch data in batches of 100 depending on the current position of the foreach current item in the loop.
Any pointer or suggestion will be appreciated.
I would suggest you to use OpenXML to parse and read your excel data from file.
This will also allow you to read out specific sections/regions from your workbook.
You will find more information and also an example at this link:
Microsoft Docs - Parse and read a large spreadsheet document (Open XML SDK)
This will be more efficiently and easier to develop than use the official microsoft office excel interop.
**I am not near a PC with Visual stuido, so this code is untested, and may have syntax errors until I can test it later.
It will still give you the main idea of what needs to be done.
private void ExcelDataPages(int firstRecord, int numberOfRecords)
{
Excel.Application dataApp = new Excel.Application();
Excel.Workbook dataWorkbook = new Excel.Workbook();
int x = 0;
dataWorkbook.DisplayAlerts = false;
dataWorkbook.Visible = false;
dataWorkbook.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityLow;
dataWorkbook = dataApp.Open(#"C:\Test\YourWorkbook.xlsx");
try
{
Excel.Worksheet dataSheet = dataWorkbook.Sheet("Name of Sheet");
while (x < numberOfRecords)
{
Range currentRange = dataSheet.Rows[firstRecord + x]; //For all columns in row
foreach (Range r in currentRange.Cells) //currentRange represents all the columns in the row
{
// do what you need to with the Data here.
}
x++;
}
}
catch (Exception ex)
{
//Enter in Error handling
}
dataWorkbook.Close(false); //Depending on how quick you will access the next batch of data, you may not want to close the Workbook, reducing load time each time. This may also mean you need to move the open of the workbook to a higher level in your class, or if this is the main process of the app, make it static, stopping the garbage collector from destroying the connection.
dataApp.Quit();
}
Give the following a try--it uses NuGet package DocumentFormat.OpenXml The code is from Using OpenXmlReader. However, I modified it to add data to a DataTable. Since you're reading data from the same Excel file multiple times, it's faster to open the Excel file once using an instance of SpreadSheetDocument and dispose of it when finished. Since the instance of SpreedSheetDocument needs to be disposed of before your application exits, IDisposable is used.
Where it says "ToDo", you'll need to replace the code that creates the DataTable columns with your own code to create the correct columns for your project.
I tested the code below with an Excel file containing approximately 15,000 rows. When reading 100 rows at a time, the first read took approximately 500 ms - 800 ms, whereas subsequent reads took approximately 100 ms - 400 ms.
Create a class (name: HelperOpenXml)
HelperOpenXml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Data;
using System.Diagnostics;
namespace ExcelReadSpecifiedRowsUsingOpenXml
{
public class HelperOpenXml : IDisposable
{
public string Filename { get; private set; } = string.Empty;
public int RowCount { get; private set; } = 0;
private SpreadsheetDocument spreadsheetDocument = null;
private DataTable dt = null;
public HelperOpenXml(string filename)
{
this.Filename = filename;
}
public void Dispose()
{
if (spreadsheetDocument != null)
{
try
{
spreadsheetDocument.Dispose();
dt.Clear();
}
catch(Exception ex)
{
throw ex;
}
}
}
public DataTable GetRowsSax(int startRow, int endRow, bool firstRowIsHeader = false)
{
int startIndex = startRow;
int endIndex = endRow;
if (firstRowIsHeader)
{
//if first row is header, increment by 1
startIndex = startRow + 1;
endIndex = endRow + 1;
}
if (spreadsheetDocument == null)
{
//create new instance
spreadsheetDocument = SpreadsheetDocument.Open(Filename, false);
//create new instance
dt = new DataTable();
//ToDo: replace 'dt.Columns.Add(...)' below with your code to create the DataTable columns
//add columns to DataTable
dt.Columns.Add("A");
dt.Columns.Add("B");
dt.Columns.Add("C");
dt.Columns.Add("D");
dt.Columns.Add("E");
dt.Columns.Add("F");
dt.Columns.Add("G");
dt.Columns.Add("H");
dt.Columns.Add("I");
dt.Columns.Add("J");
dt.Columns.Add("K");
}
else
{
//remove existing data from DataTable
dt.Rows.Clear();
}
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
int numWorkSheetParts = 0;
foreach (WorksheetPart worksheetPart in workbookPart.WorksheetParts)
{
using (OpenXmlReader reader = OpenXmlReader.Create(worksheetPart))
{
int rowIndex = 0;
//use the reader to read the XML
while (reader.Read())
{
if (reader.ElementType == typeof(Row))
{
reader.ReadFirstChild();
List<string> cValues = new List<string>();
int colIndex = 0;
do
{
//only get data from desired rows
if ((rowIndex > 0 && rowIndex >= startIndex && rowIndex <= endIndex) ||
(rowIndex == 0 && !firstRowIsHeader && rowIndex >= startIndex && rowIndex <= endIndex))
{
if (reader.ElementType == typeof(Cell))
{
Cell c = (Cell)reader.LoadCurrentElement();
string cellRef = c.CellReference; //ex: A1, B1, ..., A2, B2
string cellValue = string.Empty;
//string/text data is stored in SharedString
if (c.DataType != null && c.DataType == CellValues.SharedString)
{
SharedStringItem ssi = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(int.Parse(c.CellValue.InnerText));
cellValue = ssi.Text.Text;
}
else
{
cellValue = c.CellValue.InnerText;
}
//Debug.WriteLine("{0}: {1} ", c.CellReference, cellValue);
//add value to List which is used to add a row to the DataTable
cValues.Add(cellValue);
}
}
colIndex += 1; //increment
} while (reader.ReadNextSibling());
if (cValues.Count > 0)
{
//if List contains data, use it to add row to DataTable
dt.Rows.Add(cValues.ToArray());
}
rowIndex += 1; //increment
if (rowIndex > endIndex)
{
break; //exit loop
}
}
}
}
numWorkSheetParts += 1; //increment
}
DisplayDataTableData(dt); //display data in DataTable
return dt;
}
private void DisplayDataTableData(DataTable dt)
{
foreach (DataColumn dc in dt.Columns)
{
Debug.WriteLine("colName: " + dc.ColumnName);
}
foreach (DataRow r in dt.Rows)
{
Debug.WriteLine(r[0].ToString() + " " + r[1].ToString());
}
}
}
}
Usage:
private string excelFilename = #"C:\Temp\Test.xlsx";
private HelperOpenXml helperOpenXml = null;
...
private void GetData(int startIndex, int endIndex, bool firstRowIsHeader)
{
helperOpenXml.GetRowsSax(startIndex, endIndex, firstRowIsHeader);
}
Note: Make sure to call Dispose() (ex: helperOpenXml.Dispose();) before your application exits.
Update:
OpenXML stores dates as the number of days since 01 Jan 1900. For dates prior to 01 Jan 1900, they are stored in SharedString. For more info see Reading a date from xlsx using open xml sdk
Here's a code snippet:
Cell c = (Cell)reader.LoadCurrentElement();
...
string cellValue = string.Empty
...
cellValue = c.CellValue.InnerText;
double dateCellValue = 0;
Double.TryParse(cellValue, out dateCellValue);
DateTime dt = DateTime.FromOADate(dateCellValue);
cellValue = dt.ToString("yyyy/MM/dd");
Another simple alternative is this: Take a look at the NUGET package ExcelDataReader, with additional information on
https://github.com/ExcelDataReader/ExcelDataReader
Usage example:
[Fact]
void Test_ExcelDataReader()
{
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
var scriptPath = Path.GetDirectoryName(Util.CurrentQueryPath); // LinqPad script path
var filePath = $#"{scriptPath}\TestExcel.xlsx";
using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
{
// Auto-detect format, supports:
// - Binary Excel files (2.0-2003 format; *.xls)
// - OpenXml Excel files (2007 format; *.xlsx, *.xlsb)
using (var reader = ExcelDataReader.ExcelReaderFactory.CreateReader(stream))
{
var result = reader.AsDataSet();
// The result of each spreadsheet is in result.Tables
var t0 = result.Tables[0];
Assert.True(t0.Rows[0][0].Dump("R0C0").ToString()=="Hello", "Expected 'Hello'");
Assert.True(t0.Rows[0][1].Dump("R0C1").ToString()=="World!", "Expected 'World!'");
} // using
} // using
} // fact
Before you start reading, you need to set and encoding provider as follows:
System.Text.Encoding.RegisterProvider(
System.Text.CodePagesEncodingProvider.Instance);
The cells are addressed the following way:
var t0 = result.Tables[0]; // table 0 is the first worksheet
var cell = t0.Rows[0][0]; // on table t0, read cell row 0 column 0
And you can easily loop through the rows and columns in a for loop as follows:
for (int r = 0; r < t0.Rows.Count; r++)
{
var row = t0.Rows[r];
var columns = row.ItemArray;
for (int c = 0; c < columns.Length; c++)
{
var cell = columns[c];
cell.Dump();
}
}
I use this code with EPPlus DLL, Don't forget to add reference. But should check to match with your requirement.
public DataTable ReadExcelDatatable(bool hasHeader = true)
{
using (var pck = new OfficeOpenXml.ExcelPackage())
{
using (var stream = File.OpenRead(this._fullPath))
{
pck.Load(stream);
}
var ws = pck.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
int i = 1;
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
//table head
tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
tbl.Columns.Add(_tableHead[i]);
i++;
}
var startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
return tbl;
}
}
I'm going to give you a different answer. If the performance is bad loading a million rows into a DataTable resort to using a Driver to load the data: How to open a huge excel file efficiently
DataSet excelDataSet = new DataSet();
string filePath = #"c:\temp\BigBook.xlsx";
// For .XLSXs we use =Microsoft.ACE.OLEDB.12.0;, for .XLS we'd use Microsoft.Jet.OLEDB.4.0; with "';Extended Properties=\"Excel 8.0;HDR=YES;\"";
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + filePath + "';Extended Properties=\"Excel 12.0;HDR=YES;\"";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
OleDbDataAdapter objDA = new System.Data.OleDb.OleDbDataAdapter
("select * from [Sheet1$]", conn);
objDA.Fill(excelDataSet);
//dataGridView1.DataSource = excelDataSet.Tables[0];
}
Next filter the DataSet's DataTable using a DataView. Using a DataView's RowFilter property you can specify subsets of rows based on their column values.
DataView prodView = new DataView(excelDataSet.Tables[0],
"UnitsInStock <= ReorderLevel",
"SupplierID, ProductName",
DataViewRowState.CurrentRows);
Ref: https://www.c-sharpcorner.com/article/dataview-in-C-Sharp/
Or you could use the DataTables' DefaultView RowFilter directly:
excelDataSet.Tables[0].DefaultView.RowFilter = "Amount >= 5000 and Amount <= 5999 and Name = 'StackOverflow'";
I have an .xlsx file stored on my desktop that my C# program reads from, then it loads each worksheet into datatables that my program uses. When a modification is made to a dataTable, I save to the .xlsx file by first loading the datatable back into the worksheet, and then saving the excelPackage with the modified dataTable information.
The problem is, I sometimes need to overwrite a cell with a blank string, and after saving, the previous value is still there.
It will let me update a value to a space (" "), but I want to save the cell as empty, "", or null.
This is loading my dataTables from the .xlsx
using (var pck = new OfficeOpenXml.ExcelPackage())
{
try
{
using (var stream = File.OpenRead(filePath + "/dataSet.xlsx"))
{
pck.Load(stream);
}
for (int i = 1; i < pck.Workbook.Worksheets.Count; i++)
{
var ws = pck.Workbook.Worksheets[i];
DataTable tbl = new DataTable();
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
tbl.Columns.Add(true ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = true ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
if (ws.Name == "customerDataTable") { _customerDataTable = tbl; }
else if (ws.Name == "vehicleDataTable") { _vehicleDataTable = tbl; }
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
This is saving the dataTable information into worksheet, then to .xlsx
string tableName = "";
if (table == _customerDataTable) { tableName = "customerDataTable"; }
else if (table == _vehicleDataTable) { tableName = "vehicleDataTable"; }
FileInfo file = new FileInfo(filePath + "/dataSet.xlsx");
using (ExcelPackage excelPackage = new ExcelPackage(file))
{
ExcelWorkbook excelWorkBook = excelPackage.Workbook;
ExcelWorksheet excelWorksheet = excelWorkBook.Worksheets[tableName];
excelWorksheet.Cells.LoadFromDataTable(table, true);
excelPackage.Save();
}
I got it to work following VDWWDs post, using the following code:
for (int i = 0; i < table.Rows.Count; i++)
{
for (int j = 0; j < table.Columns.Count; j++)
{
excelWorksheet.Cells[i+2,j+1].Value = table.Rows[i][j];
}
}
//excelWorksheet.Cells.LoadFromDataTable(table, true);
I replaced the LoadFromTable() line with a nested For loop. Although it functionally works, I'm going to be using this method a lot throughout my program, and this solution seems a bit bulky compared to EPPlus LoadFromTable method. I'm thinking there has to be a better way...
I'm generating a number of excel documents with EPPlus and I'm running into some difficulties with the formatting.
I have used
xlWorkSheet.Cells.AutoFitColumns();
and this seems to work for the data, but does not autosize for the column names. For instance I will open up the file and I can see the column names bunched up. I can also click on the border of a column and it will expand the column more. In fact I can do this about 5 times before it seems to reach its maximum for autosizing. Essentially I want to programmatically set each column so that it's at this maximum (I've even tried applying AutoFitColumns multiple times, however this made no difference).
Is there a way to do this?
Note that I can't just hardcode the column widths as I'm trying to reuse the same code for multiple files.
EDIT: Here's my code generalised
private void GeneralTest()
{
var ReportName = "myReport"
int ReportID = 123
var SelectedMonth = "April 2018"
var LAGroup = "all"
var fileName = $"{ReportName}_{SelectedMonth}_{LAGroup}.xlsx";
// Remove all illegal characters and replace with underscores
var[] disallowedCharacters = new[] { "/", #"\", "?", "%", "*", ":", "|", "\"", "<", ">" };
foreach (var character in disallowedCharacters)
fileName = fileName.Replace(character, "_");
var filePath = $#"c:\Test\{fileName}";
if (File.Exists(filePath))
File.Delete(filePath);
FileInfo NewFile = new FileInfo(filePath);
using (ExcelPackage MyExcel = new ExcelPackage(NewFile))
{
var myTestdt = MyGetDataFunction(ReportID, DateTime.Parse(SelectedMonth));
ExcelWorksheet xlWorkSheet;
xlWorkSheet = MyExcel.Workbook.Worksheets.Add("Template");
xlWorkSheet.Name = "Template";
xlWorkSheet.Cells("A1").LoadFromDataTable(myTestdt, true);
var formatRange = xlWorkSheet.Cells(1, 1, 1, myTestdt.Columns.Count);
formatRange.Style.Font.Bold = true;
formatRange.Style.Fill.PatternType = Style.ExcelFillStyle.Solid;
formatRange.Style.Fill.BackgroundColor.SetColor(System.Drawing.ColorTranslator.FromHtml("#CDFFCC"));
formatRange.Style.Font.Size = 10;
formatRange.Style.Font.Name = "Arial";
formatRange.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
formatRange.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
formatRange.Style.WrapText = true;
formatRange.AutoFilter = true;
for (int index = 0; index <= myTestdt.Columns.Count - 1; index++)
{
if (myTestdt.Columns(index).DataType.Name == "DateTime")
{
formatRange = xlWorkSheet.Cells(2, index + 1, myTestdt.Rows.Count, index + 1);
formatRange.Style.Numberformat.Format = "dd/mm/yyyy";
}
}
xlWorkSheet.View.FreezePanes(2, 2);
xlWorkSheet.Cells.AutoFitColumns();
MyExcel.SaveAs(NewFile);
}
}
This is a simple class I wrote to create an Excel from a DataSet.
Please note that I intentionally avoided catching the exceptions because I do that in the caller.
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ds2Xlsx
{
public class Ds2ExcelEngine
{
public static void CreateExcel(
DataSet ds,
string path,
OfficeOpenXml.Table.TableStyles tableStyle = OfficeOpenXml.Table.TableStyles.Light9,
bool autofitColumns = true)
{
if (ds != null)
{
using (ExcelPackage ep = new ExcelPackage())
{
foreach (DataTable dt in ds.Tables)
{
AddTableWorksheet(tableStyle, autofitColumns, ep, dt);
}
ep.SaveAs(new System.IO.FileInfo(path));
}
}
}
private static void AddTableWorksheet(OfficeOpenXml.Table.TableStyles tableStyle, bool autofitColumns, ExcelPackage ep, DataTable dt)
{
ExcelWorksheet ew = ep.Workbook.Worksheets.Add(dt.TableName);
int row = 1;
int column = 1;
foreach (DataColumn dc in dt.Columns)
{
ew.Cells[row, column].Value = dc.Caption;
column++;
}
foreach (DataRow dr in dt.Rows)
{
column = 1;
row++;
foreach (DataColumn dc in dt.Columns)
{
ew.Cells[row, column].Value = dr[dc];
column++;
}
}
column = 1;
foreach (DataColumn dc in dt.Columns)
{
if (dc.DataType == typeof(DateTime))
{
ew.Cells[1, column, row, column].Style.Numberformat.Format = DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
}
column++;
}
var excelTable = ew.Tables.Add(new ExcelAddressBase(1, 1, row, column - 1), $"tbl_{ dt.TableName }");
excelTable.TableStyle = tableStyle;
if (autofitColumns)
{
ew.Cells[ew.Dimension.Address].AutoFitColumns();
}
}
}
}
When I open the Excel I created, all the columns are shown correctly, either headers or content.
I ran into almost the same problem and this did solved it for me:
ew.Cells[ew.Dimension.Address].AutoFitColumns();
This does AutoFit the columns to smaller & wider when there's need for it.
I am looking to export an excel sheet using NPOI library. Is there any way to insert the datatable into the sheet without losing the data format?
Previously, I used to use the Gembox Spreadsheet Library. This worked well for me. The code for that looke like:
public void ExportTest(DataSet ds)
{
SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
ExcelFile ef = new ExcelFile();
var filename = DateTime.Now.ToString("yyyyMMdd") + "BSI_MEMBERAmendment" + ".xls";
foreach (DataTable dt in ds.Tables)
{
ExcelWorksheet ws = ef.Worksheets.Add(dt.TableName);
ws.InsertDataTable(dt,
new InsertDataTableOptions(0, 0)
{
ColumnHeaders = true,
StartRow = 0,
});
}
ef.Save(this.Response, filename);
I had to stop using the Gembox library because I need to make excel files with more than 5 sheets. Gembox, unfortunately does not allow that on a free platform. As such, I've switched to NPOI.
Now that I'm using the NPOI library, I've change my code to:
public void WriteExcelWithNPOI(String extension, DataSet dataSet)
{
HSSFWorkbook workbook = new HSSFWorkbook(); ;
if (extension == "xls")
{
workbook = new HSSFWorkbook();
}
else
{
throw new Exception("This format is not supported");
}
foreach (DataTable dt in dataSet.Tables)
{
var sheet1 = workbook.CreateSheet(dt.TableName);
// How can i insert the data's from dataTable in this sheet
}
using (var exportData = new MemoryStream())
{
Response.Clear();
workbook.Write(exportData);
if (extension == "xls")
{
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", "tpms_dict.xls"));
Response.BinaryWrite(exportData.GetBuffer());
}
Response.End();
}
}
The problem that I'm encountering with using the NPOI library is, all the cells in the exported excel file is formatted as text. I'd like to retain the format that's used in the data table.
Looking for help. Thanks in advance!!!
To insert data from a data table, you could perhaps use this code in place of the comment "// How can i insert the data's from dataTable in this sheet".
// 1. make a header row
IRow row1 = sheet1.CreateRow(0);
for (int j = 0; j < dt.Columns.Count; j++)
{
ICell cell = row1.CreateCell(j);
string columnName = dt.Columns[j].ToString();
cell.SetCellValue(columnName);
}
// 2. loop through data
for (int i = 0; i < dt.Rows.Count; i++)
{
IRow row = sheet1.CreateRow(i + 1);
for (int j = 0; j < dt.Columns.Count; j++)
{
ICell cell = row.CreateCell(j);
string columnName = dt.Columns[j].ToString();
cell.SetCellValue(dt.Rows[i][columnName].ToString());
}
}
// 3. Auto size columns
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < row1.LastCellNum; j++)
{
sheet1.AutoSizeColumn(j);
}
}
For data types, you could use the function cell.SetCellType(CellType.[TYPE HERE]);. The type entered in the function SetCellType must match the data type in cell.SetCellValue() afterwards.
This will modify the data loop to look as follows:
// 2. loop through data
for (int i = 0; i < dt.Rows.Count; i++)
{
IRow row = sheet1.CreateRow(i + 1);
for (int j = 0; j < dt.Columns.Count; j++)
{
ICell cell = row.CreateCell(j);
string columnName = dt.Columns[j].ToString();
// Set the cell type
cell.SetCellType(GetCorrectCellType(dt.Rows[i][columnName].GetType()))
// Set the cell value
cell.SetCellValue(dt.Rows[i][columnName]);
}
}
// Function to return the correct cell type
public int GetCorrectCellType(Type dataType)
{
if(dataType == typeof(string))
return CellType.String;
else if(dataType == typeof(int) || dataType == typeof(double))
return CellType.Numeric;
else if(dataType == typeof(bool))
return CellType.Boolean;
else
return CellType.Unknown; // Not sure how to set Date Type --> Unknown
}
EDIT
I found how set set Date values in a human readable format in this answer.
I know I am a little late here but I think it may help others, yes, there is a way to convert datatable directly to export excel without losing data format.
I have developed an excel utility with the use of the NPOI package, which can
Simply takes your data table or the collection
And Returns you excel while maintaining all the data table/list data type intact in the excel.
Github Code repo.: https://github.com/ansaridawood/.NET-Generic-Excel-Export-Sample/tree/master/GenericExcelExport/ExcelExport
Looking for a code explanation, you can find it here:
https://www.codeproject.com/Articles/1241654/Export-to-Excel-using-NPOI-Csharp-and-WEB-API
It uses NPOI DLL and it has 2 cs files to include and then you are good to go
Below is the first file for reference AbstractDataExport.cs:
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
namespace GenericExcelExport.ExcelExport
{
public interface IAbstractDataExport
{
HttpResponseMessage Export(List exportData, string fileName, string sheetName);
}
public abstract class AbstractDataExport : IAbstractDataExport
{
protected string _sheetName;
protected string _fileName;
protected List _headers;
protected List _type;
protected IWorkbook _workbook;
protected ISheet _sheet;
private const string DefaultSheetName = "Sheet1";
public HttpResponseMessage Export
(List exportData, string fileName, string sheetName = DefaultSheetName)
{
_fileName = fileName;
_sheetName = sheetName;
_workbook = new XSSFWorkbook(); //Creating New Excel object
_sheet = _workbook.CreateSheet(_sheetName); //Creating New Excel Sheet object
var headerStyle = _workbook.CreateCellStyle(); //Formatting
var headerFont = _workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
WriteData(exportData); //your list object to NPOI excel conversion happens here
//Header
var header = _sheet.CreateRow(0);
for (var i = 0; i < _headers.Count; i++)
{
var cell = header.CreateCell(i);
cell.SetCellValue(_headers[i]);
cell.CellStyle = headerStyle;
}
for (var i = 0; i < _headers.Count; i++)
{
_sheet.AutoSizeColumn(i);
}
using (var memoryStream = new MemoryStream()) //creating memoryStream
{
_workbook.Write(memoryStream);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memoryStream.ToArray())
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue
("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = $"{_fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
};
return response;
}
}
//Generic Definition to handle all types of List
public abstract void WriteData(List exportData);
}
}
and this the second and final file AbstractDataExportBridge.cs:
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;
namespace GenericExcelExport.ExcelExport
{
public class AbstractDataExportBridge : AbstractDataExport
{
public AbstractDataExportBridge()
{
_headers = new List<string>();
_type = new List<string>();
}
public override void WriteData<T>(List<T> exportData)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
{
var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
_type.Add(type.Name);
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ??
prop.PropertyType);
string name = Regex.Replace(prop.Name, "([A-Z])", " $1").Trim(); //space separated
//name by caps for header
_headers.Add(name);
}
foreach (T item in exportData)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
IRow sheetRow = null;
for (int i = 0; i < table.Rows.Count; i++)
{
sheetRow = _sheet.CreateRow(i + 1);
for (int j = 0; j < table.Columns.Count; j++)
{
ICell Row1 = sheetRow.CreateCell(j);
string type = _type[j].ToLower();
var currentCellValue = table.Rows[i][j];
if (currentCellValue != null &&
!string.IsNullOrEmpty(Convert.ToString(currentCellValue)))
{
if (type == "string")
{
Row1.SetCellValue(Convert.ToString(currentCellValue));
}
else if (type == "int32")
{
Row1.SetCellValue(Convert.ToInt32(currentCellValue));
}
else if (type == "double")
{
Row1.SetCellValue(Convert.ToDouble(currentCellValue));
}
}
else
{
Row1.SetCellValue(string.Empty);
}
}
}
}
}
}
For a detailed explanation, refer link provided in the beginning.
I have a DataTable with 30+ columns and 6500+ rows.I need to dump the whole DataTable values into an Excel file.Can anyone please help with the C# code.I need each column value to be in a cell.To be precise,I need the exact looking copy of DataTable in an Excel File.Please help.
Thanks,
Vix
use this code...
dt = city.GetAllCity();//your datatable
string attachment = "attachment; filename=city.xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in dt.Columns)
{
Response.Write(tab + dc.ColumnName);
tab = "\t";
}
Response.Write("\n");
int i;
foreach (DataRow dr in dt.Rows)
{
tab = "";
for (i = 0; i < dt.Columns.Count; i++)
{
Response.Write(tab + dr[i].ToString());
tab = "\t";
}
Response.Write("\n");
}
Response.End();
This snippet could be faster to implement:
// Example data
DataTable table = new DataTable();
table.Columns.AddRange(new[]{ new DataColumn("Key"), new DataColumn("Value") });
foreach (string name in Request.ServerVariables)
table.Rows.Add(name, Request.ServerVariables[name]);
// This actually makes your HTML output to be downloaded as .xls file
Response.Clear();
Response.ClearContent();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=ExcelFile.xls");
// Create a dynamic control, populate and render it
GridView excel = new GridView();
excel.DataSource = table;
excel.DataBind();
excel.RenderControl(new HtmlTextWriter(Response.Output));
Response.Flush();
Response.End();
Below link is used to export datatable to excel in C# Code.
http://royalarun.blogspot.in/2012/01/export-datatable-to-excel-in-c-windows.html
using System;
using System.Data;
using System.IO;
using System.Windows.Forms;
namespace ExportExcel
{
public partial class ExportDatatabletoExcel : Form
{
public ExportDatatabletoExcel()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
//Add Datacolumn
DataColumn workCol = dt.Columns.Add("FirstName", typeof(String));
dt.Columns.Add("LastName", typeof(String));
dt.Columns.Add("Blog", typeof(String));
dt.Columns.Add("City", typeof(String));
dt.Columns.Add("Country", typeof(String));
//Add in the datarow
DataRow newRow = dt.NewRow();
newRow["firstname"] = "Arun";
newRow["lastname"] = "Prakash";
newRow["Blog"] = "http://royalarun.blogspot.com/";
newRow["city"] = "Coimbatore";
newRow["country"] = "India";
dt.Rows.Add(newRow);
//open file
StreamWriter wr = new StreamWriter(#"D:\\Book1.xls");
try
{
for (int i = 0; i < dt.Columns.Count; i++)
{
wr.Write(dt.Columns[i].ToString().ToUpper() + "\t");
}
wr.WriteLine();
//write rows to excel file
for (int i = 0; i < (dt.Rows.Count); i++)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
if (dt.Rows[i][j] != null)
{
wr.Write(Convert.ToString(dt.Rows[i][j]) + "\t");
}
else
{
wr.Write("\t");
}
}
//go to next line
wr.WriteLine();
}
//close file
wr.Close();
}
catch (Exception ex)
{
throw ex;
}
}
}
}
The most rank answer in this post work, however its is CSV file. It is not actual Excel file. Therefore, you will get a warning when you are opening a file.
The best solution I found on the web is using CloseXML
https://github.com/closedxml/closedxml
You need to Open XML as well.
dt = city.GetAllCity();//your datatable
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(dt);
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=GridView.xlsx");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
MyMemoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
Credit: http://www.aspsnippets.com/Articles/Solution-ASPNet-GridView-Export-to-Excel-The-file-you-are-trying-to-open-is-in-a-different-format-than-specified-by-the-file-extension.aspx
I use This in page.`
public void DTToExcel(DataTable dt)
{
// dosya isimleri ileride aynı anda birden fazla kullanıcı aynı dosya üzerinde işlem yapmak ister düşüncesiyle guid yapıldı.
string FileName = Guid.NewGuid().ToString();
FileInfo f = new FileInfo(Server.MapPath("Downloads") + string.Format("\\{0}.xlsx", FileName));
if (f.Exists)
f.Delete(); // delete the file if it already exist.
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearHeaders();
response.ClearContent();
response.Charset = Encoding.UTF8.WebName;
response.AddHeader("content-disposition", "attachment; filename=" + FileName + ".xls");
response.AddHeader("Content-Type", "application/Excel");
response.ContentType = "application/vnd.xlsx";
//response.AddHeader("Content-Length", file.Length.ToString());
// create a string writer
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw)) //datatable'a aldığımız sorguyu bir datagrid'e atayıp html'e çevir.
{
// instantiate a datagrid
DataGrid dg = new DataGrid();
dg.DataSource = dt;
dg.DataBind();
dg.RenderControl(htw);
response.Write(sw.ToString());
dg.Dispose();
dt.Dispose();
response.End();
}
}
}
var lines = new List<string>();
string[] columnNames = dt.Columns.Cast<DataColumn>().
Select(column => column.ColumnName).
ToArray();
var header = string.Join(",", columnNames);
lines.Add(header);
var valueLines = dt.AsEnumerable()
.Select(row => string.Join(",", row.ItemArray));
lines.AddRange(valueLines);
File.WriteAllLines("excel.csv", lines);
Here dt refers to your DataTable pass as a paramter
While not a .NET implementation, you may find that the plug-in TableTools may be highly effective depending on your audience. It relies upon flash which shouldn't be a problem for most cases of needing to actually work in-depth and then want to record tabular information.
The latest version appears to support copying to clipboard, into a CSV, ".XLS" (really just a tab-delimited file named .xls), to a PDF, or create a printer friendly page version with all rows displayed and the rest of your page's contents hidden.
I found the extension on the DataTables site here: http://datatables.net/extras/tabletools/
The download is available in the plug-ins (extras) page here: http://datatables.net/extras/
It supposedly is downloaded as a part of DataTables (hence the phrase "Extras included in the DataTables package") but I didn't find it in the download I have been using. Seems to work wonderfully!
Most answers are actually producing the CSV which I don't always have good experience with, when opening in Excel.
One way of doing it would be also with ACE OLEDB Provider (see also connection strings for Excel). Of course you'd have to have the provider installed and registered. You do have it, if you have Excel installed, but this is something you have to consider when deploying (e.g. on web server).
In below helper class code you'd have to call something like ExportHelper.CreateXlsFromDataTable(dataset.Tables[0], #"C:\tmp\export.xls");
public class ExportHelper
{
private const string ExcelOleDbConnectionStringTemplate = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=YES\";";
/// <summary>
/// Creates the Excel file from items in DataTable and writes them to specified output file.
/// </summary>
public static void CreateXlsFromDataTable(DataTable dataTable, string fullFilePath)
{
string createTableWithHeaderScript = GenerateCreateTableCommand(dataTable);
using (var conn = new OleDbConnection(String.Format(ExcelOleDbConnectionStringTemplate, fullFilePath)))
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
OleDbCommand cmd = new OleDbCommand(createTableWithHeaderScript, conn);
cmd.ExecuteNonQuery();
foreach (DataRow dataExportRow in dataTable.Rows)
{
AddNewRow(conn, dataExportRow);
}
}
}
private static void AddNewRow(OleDbConnection conn, DataRow dataRow)
{
string insertCmd = GenerateInsertRowCommand(dataRow);
using (OleDbCommand cmd = new OleDbCommand(insertCmd, conn))
{
AddParametersWithValue(cmd, dataRow);
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// Generates the insert row command.
/// </summary>
private static string GenerateInsertRowCommand(DataRow dataRow)
{
var stringBuilder = new StringBuilder();
var columns = dataRow.Table.Columns.Cast<DataColumn>().ToList();
var columnNamesCommaSeparated = string.Join(",", columns.Select(x => x.Caption));
var questionmarkCommaSeparated = string.Join(",", columns.Select(x => "?"));
stringBuilder.AppendFormat("INSERT INTO [{0}] (", dataRow.Table.TableName);
stringBuilder.Append(columnNamesCommaSeparated);
stringBuilder.Append(") VALUES(");
stringBuilder.Append(questionmarkCommaSeparated);
stringBuilder.Append(")");
return stringBuilder.ToString();
}
/// <summary>
/// Adds the parameters with value.
/// </summary>
private static void AddParametersWithValue(OleDbCommand cmd, DataRow dataRow)
{
var paramNumber = 1;
for (int i = 0; i <= dataRow.Table.Columns.Count - 1; i++)
{
if (!ReferenceEquals(dataRow.Table.Columns[i].DataType, typeof(int)) && !ReferenceEquals(dataRow.Table.Columns[i].DataType, typeof(decimal)))
{
cmd.Parameters.AddWithValue("#p" + paramNumber, dataRow[i].ToString().Replace("'", "''"));
}
else
{
object value = GetParameterValue(dataRow[i]);
OleDbParameter parameter = cmd.Parameters.AddWithValue("#p" + paramNumber, value);
if (value is decimal)
{
parameter.OleDbType = OleDbType.Currency;
}
}
paramNumber = paramNumber + 1;
}
}
/// <summary>
/// Gets the formatted value for the OleDbParameter.
/// </summary>
private static object GetParameterValue(object value)
{
if (value is string)
{
return value.ToString().Replace("'", "''");
}
return value;
}
private static string GenerateCreateTableCommand(DataTable tableDefination)
{
StringBuilder stringBuilder = new StringBuilder();
bool firstcol = true;
stringBuilder.AppendFormat("CREATE TABLE [{0}] (", tableDefination.TableName);
foreach (DataColumn tableColumn in tableDefination.Columns)
{
if (!firstcol)
{
stringBuilder.Append(", ");
}
firstcol = false;
string columnDataType = "CHAR(255)";
switch (tableColumn.DataType.Name)
{
case "String":
columnDataType = "CHAR(255)";
break;
case "Int32":
columnDataType = "INTEGER";
break;
case "Decimal":
// Use currency instead of decimal because of bug described at
// http://social.msdn.microsoft.com/Forums/vstudio/en-US/5d6248a5-ef00-4f46-be9d-853207656bcc/localization-trouble-with-oledbparameter-and-decimal?forum=csharpgeneral
columnDataType = "CURRENCY";
break;
}
stringBuilder.AppendFormat("{0} {1}", tableColumn.ColumnName, columnDataType);
}
stringBuilder.Append(")");
return stringBuilder.ToString();
}
}
Working code for Excel Export
try
{
DataTable dt = DS.Tables[0];
string attachment = "attachment; filename=log.xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in dt.Columns)
{
Response.Write(tab + dc.ColumnName);
tab = "\t";
}
Response.Write("\n");
int i;
foreach (DataRow dr in dt.Rows)
{
tab = "";
for (i = 0; i < dt.Columns.Count; i++)
{
Response.Write(tab + dr[i].ToString());
tab = "\t";
}
Response.Write("\n");
}
Response.End();
}
catch (Exception Ex)
{ }
Try this to export the data to Excel file same as in DataTable and could customize also.
dtDataTable1 = ds.Tables[0];
try
{
Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
Workbook xlWorkBook = ExcelApp.Workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);
for (int i = 1; i > 0; i--)
{
Sheets xlSheets = null;
Worksheet xlWorksheet = null;
//Create Excel sheet
xlSheets = ExcelApp.Sheets;
xlWorksheet = (Worksheet)xlSheets.Add(xlSheets[1], Type.Missing, Type.Missing, Type.Missing);
xlWorksheet.Name = "MY FIRST EXCEL FILE";
for (int j = 1; j < dtDataTable1.Columns.Count + 1; j++)
{
ExcelApp.Cells[i, j] = dtDataTable1.Columns[j - 1].ColumnName;
ExcelApp.Cells[1, j].Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Green);
ExcelApp.Cells[i, j].Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.WhiteSmoke);
}
// for the data of the excel
for (int k = 0; k < dtDataTable1.Rows.Count; k++)
{
for (int l = 0; l < dtDataTable1.Columns.Count; l++)
{
ExcelApp.Cells[k + 2, l + 1] = dtDataTable1.Rows[k].ItemArray[l].ToString();
}
}
ExcelApp.Columns.AutoFit();
}
((Worksheet)ExcelApp.ActiveWorkbook.Sheets[ExcelApp.ActiveWorkbook.Sheets.Count]).Delete();
ExcelApp.Visible = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
If you to export datatable to excel with formatted header text try like this.
public void ExportFullDetails()
{
Int16 id = Convert.ToInt16(Session["id"]);
DataTable registeredpeople = new DataTable();
registeredpeople = this.dataAccess.ExportDetails(eventid);
string attachment = "attachment; filename=Details.xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/vnd.ms-excel";
string tab = "";
registeredpeople.Columns["Reg_id"].ColumnName = "Reg. ID";
registeredpeople.Columns["Name"].ColumnName = "Name";
registeredpeople.Columns["Reg_country"].ColumnName = "Country";
registeredpeople.Columns["Reg_city"].ColumnName = "City";
registeredpeople.Columns["Reg_email"].ColumnName = "Email";
registeredpeople.Columns["Reg_business_phone"].ColumnName = "Business Phone";
registeredpeople.Columns["Reg_mobile"].ColumnName = "Mobile";
registeredpeople.Columns["PositionRole"].ColumnName = "Position";
registeredpeople.Columns["Reg_work_type"].ColumnName = "Work Type";
foreach (DataColumn dc in registeredpeople.Columns)
{
Response.Write(tab + dc.ColumnName);
tab = "\t";
}
Response.Write("\n");
int i;
foreach (DataRow dr in registeredpeople.Rows)
{
tab = "";
for (i = 0; i < registeredpeople.Columns.Count; i++)
{
Response.Write(tab + dr[i].ToString());
tab = "\t";
}
Response.Write("\n");
}
Response.End();
}
I have done the DataTable to Excel conversion with the following code. Hope it's very easy no need to change more just copy & pest the code replace your variable with your variable, and it will work properly.
First create a folder in your solution Document, and create an Excel file MyTemplate.xlsx. you can change those name according to your requirement. But remember for that you have to change the name in code also.
Please find the following code...
protected void GetExcel_Click(object sender, EventArgs e)
{
ManageTicketBS objManageTicket = new ManageTicketBS();
DataTable DT = objManageTicket.GetAlldataByDate(); //this function will bring the data in DataTable format, you can use your function instate of that.
string DownloadFileName;
string FolderPath;
string FileName = "MyTemplate.xlsx";
DownloadFileName = Path.GetFileNameWithoutExtension(FileName) + new Random().Next(10000, 99999) + Path.GetExtension(FileName);
FolderPath = ".\\" + DownloadFileName;
GetParents(Server.MapPath("~/Document/" + FileName), Server.MapPath("~/Document/" + DownloadFileName), DT);
string path = Server.MapPath("~/Document/" + FolderPath);
FileInfo file = new FileInfo(path);
if (file.Exists)
{
try
{
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Buffer = true;
response.ContentType = MimeType(Path.GetExtension(FolderPath));
response.AddHeader("Content-Disposition", "attachment;filename=" + DownloadFileName);
byte[] data = File.ReadAllBytes(path);
response.BinaryWrite(data);
HttpContext.Current.ApplicationInstance.CompleteRequest();
response.End();
}
catch (Exception ex)
{
ex.ToString();
}
finally
{
DeleteOrganisationtoSupplierTemplate(path);
}
}
}
public string GetParents(string FilePath, string TempFilePath, DataTable DTTBL)
{
File.Copy(Path.Combine(FilePath), Path.Combine(TempFilePath), true);
FileInfo file = new FileInfo(TempFilePath);
try
{
DatatableToExcel(DTTBL, TempFilePath, 0);
return TempFilePath;
}
catch (Exception ex)
{
return "";
}
}
public static string MimeType(string Extension)
{
string mime = "application/octetstream";
if (string.IsNullOrEmpty(Extension))
return mime;
string ext = Extension.ToLower();
Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (rk != null && rk.GetValue("Content Type") != null)
mime = rk.GetValue("Content Type").ToString();
return mime;
}
static bool DeleteOrganisationtoSupplierTemplate(string filePath)
{
try
{
File.Delete(filePath);
return true;
}
catch (IOException)
{
return false;
}
}
public void DatatableToExcel(DataTable dtable, string pFilePath, int excelSheetIndex=1)
{
try
{
if (dtable != null && dtable.Rows.Count > 0)
{
IWorkbook workbook = null;
ISheet worksheet = null;
using (FileStream stream = new FileStream(pFilePath, FileMode.Open, FileAccess.ReadWrite))
{
workbook = WorkbookFactory.Create(stream);
worksheet = workbook.GetSheetAt(excelSheetIndex);
int iRow = 1;
foreach (DataRow row in dtable.Rows)
{
IRow file = worksheet.CreateRow(iRow);
int iCol = 0;
foreach (DataColumn column in dtable.Columns)
{
ICell cell = null;
object cellValue = row[iCol];
switch (column.DataType.ToString())
{
case "System.Boolean":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.Boolean);
if (Convert.ToBoolean(cellValue)) { cell.SetCellFormula("TRUE()"); }
else { cell.SetCellFormula("FALSE()"); }
//cell.CellStyle = _boolCellStyle;
}
break;
case "System.String":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.String);
cell.SetCellValue(Convert.ToString(cellValue));
}
break;
case "System.Int32":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.Numeric);
cell.SetCellValue(Convert.ToInt32(cellValue));
//cell.CellStyle = _intCellStyle;
}
break;
case "System.Int64":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.Numeric);
cell.SetCellValue(Convert.ToInt64(cellValue));
//cell.CellStyle = _intCellStyle;
}
break;
case "System.Decimal":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.Numeric);
cell.SetCellValue(Convert.ToDouble(cellValue));
//cell.CellStyle = _doubleCellStyle;
}
break;
case "System.Double":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.Numeric);
cell.SetCellValue(Convert.ToDouble(cellValue));
//cell.CellStyle = _doubleCellStyle;
}
break;
case "System.DateTime":
if (cellValue != DBNull.Value)
{
cell = file.CreateCell(iCol, CellType.String);
DateTime dateTime = Convert.ToDateTime(cellValue);
cell.SetCellValue(dateTime.ToString("dd/MM/yyyy"));
DateTime cDate = Convert.ToDateTime(cellValue);
if (cDate != null && cDate.Hour > 0)
{
//cell.CellStyle = _dateTimeCellStyle;
}
else
{
// cell.CellStyle = _dateCellStyle;
}
}
break;
default:
break;
}
iCol++;
}
iRow++;
}
using (var WritetoExcelfile = new FileStream(pFilePath, FileMode.Create, FileAccess.ReadWrite))
{
workbook.Write(WritetoExcelfile);
WritetoExcelfile.Close();
//workbook.Write(stream);
stream.Close();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
This code you just need to copy & pest in your script and add the Namespace as following, Also change the excel file name as previously discussed.
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.SS.Util;
Please try this, this will export your data table data's faster to excel.
Note: Range "FW", that I have hard coded is because I had 179 columns.
public void UpdateExcelApplication(SqlDataTable dataTable)
{
var objects = new string[dataTable.Rows.Count, dataTable.Columns.Count];
var rowIndex = 0;
foreach (DataRow row in dataTable.Rows)
{
var colIndex = 0;
foreach (DataColumn column in dataTable.Columns)
{
objects[rowIndex, colIndex++] = Convert.ToString(row[column]);
}
rowIndex++;
}
var range = this.workSheet.Range[$"A3:FW{dataTable.Rows.Count + 2}"];
range.Value = objects;
this.workSheet.Columns.AutoFit();
this.workSheet.Rows.AutoFit();
}