I'm exporting a DataSet to Excel (.xlsx) and for whatever reason, I'm getting an additional (unwanted) worksheet added to my workbook.
My dataTables are setup like so:
DataTable table1 = new DataTable();
table1 = CallReport("ReportName");
DataTable table2 = new DataTable();
table2 = CallReport("ReportName");
DataTable table3 = new DataTable();
table3 = CallReport("ReportName");
//add to DataSet
DataSet exportSet = new DataSet();
table3.TableName = "Combined";
exportSet.Tables.Add(table3);
table2.TableName = "Non-Services";
exportSet.Tables.Add(table2);
table1.TableName = "Services";
exportSet.Tables.Add(table1);
I'm then creating an Excel instance, then using foreach to loop through my DataSet and write the tables to the Excel workbook:
MSClass.CreateExcelFile();
foreach (DataTable table in exportSet.Tables)
{
MSClass.WriteToExcel(table, table.TableName);
}
MSClass.SaveExcelFile(exportPath);
Here is how I'm creating the Excel file, writing to it and saving it within my MSClass:
class MSClass
{
static Microsoft.Office.Interop.Excel.Application xl;
public static void CreateExcelFile()
{
//Creates new instance of Excel.Application()
xl = new Excel.Application();
//Adds new workbook to the application instance
xl.Workbooks.Add();
}
public static void SaveExcelFile(string filePath)
{
//Check to make sure the filePath isn't empty, and if it is, just show the file instance
if (filePath != null && filePath != "")
{
//in case there's an error
try
{
//Makes sure the sheet is in the active session
Excel._Worksheet sheet = xl.ActiveSheet;
//Stops from asking to overwrite the file.
//If I didn't want to overwrite I would be changing the file name everytime.
xl.DisplayAlerts = false;
//Saves the sheet to the file path
sheet.SaveAs(filePath);
//shows the final product
xl.Visible = true;
}
catch (Exception ex)
{
//throw up an Exception for any error and show the error message
throw new Exception("Export To Excel: Excel file could not be saved! Check filePath.\n" + ex.Message);
}
}
else //no file path is given
{
//Just show the current session of the Excel Application
xl.Visible = true;
}
}
public static void WriteToExcel(DataTable table, string sheetName)
{
//Adds new worksheet to workbook
Excel._Worksheet sheet = xl.ActiveWorkbook.Sheets[1];
//Gets count of columns within supplied DataTable
int colCount = table.Columns.Count;
//Creates object array for headers for each column
object[] header = new object[colCount];
//loop to add column names to header object array
for (int i = 0; i < colCount; i++)
{
//Adds column names to header object array
header[i] = table.Columns[i].ColumnName;
}
//Get range of headers
Excel.Range headerRange = sheet.get_Range((Excel.Range)(sheet.Cells[1, 1]), (Excel.Range)(sheet.Cells[1, colCount]));
//Applies the header to Excel file
headerRange.Value = header;
//Adds color to header to make more distinct
headerRange.Interior.Color = ColorTranslator.ToOle(Color.LightGray);
//Bolds the header
headerRange.Font.Bold = true;
//gets count of rows from DataTable
int rowCount = table.Rows.Count;
//Object multidimensional array for the cells within the dataTable
object[,] cells = new object[rowCount, colCount];
//Adds the cells from DataTable to cell Object array
for (int j = 0; j < rowCount; j++)
{
for (int i = 0; i < colCount; i++)
{
//Sets cell values to DataTable values
cells[j, i] = table.Rows[j][i];
}
}
//prints the cell values to Excel cell(s)
sheet.get_Range((Excel.Range)(sheet.Cells[2, 1]), (Excel.Range)(sheet.Cells[rowCount + 1, colCount])).Value = cells;
sheet.Name = sheetName;
sheet.Activate();
xl.Worksheets.Add(sheet);
}
}
I'm unsure what is currently causing the extra sheet to be exported. the sheets export in the order of: Sheet4 | Services | Non-Services | Combined
Where Sheet4 is completely blank, and the other sheets are exported in reversed order.
What is causing my extra (blank) sheet to be added to the workbook?
Related
All,
I have been struggling to simply reference an Excel file so that I can extract its data into a new worksheet automatically.
I know this means to create a new Excel file and its items:
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
Excel.Range oRng;
//Start Excel and get Application object.
oXL = new Excel.Application();
oXL.Visible = true;
//Get a new workbook.
oWB = (Excel._Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (Excel._Worksheet)oWB.ActiveSheet;
But this is where I am lost...I want the user to select another Excel file through a file dialog and then I want to copy data from said file into the new workbook above.
Ex: New file, user selects "MyExcel.csv". How would I reference this so that I can, say, copy Column A into the new worksheet? Whatever works with C#.
Maybe this helps:
Make sure your manage your Nugets and add the reference "Microsoft.Office.Interop.Excel" --> (References (Right click) --> Manage Nuget Packages --> Browse --> "Microsoft.Office.Interop.Excel" --> Install)
Note: This is is a copy paste into the same worksheet. To copy the data into another worksheet from another file just pass the "worksheet" as parameter to the method and paste it there.
public class Excel1
{
private readonly string excelSufix = ".xlsx";
private readonly string excelFilePrefix = "..."; //Where you excel file is located
private string getFilePath(string fileName)
{
return excelFilePrefix + fileName + excelSufix; //returns the file path by the given file name
}
public void CopyPaste(string fileName, int worksheet, string toCopyRange, string whereInsertRange)
{
//Range should look like = "A:C" or "D:F"
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Visible = true;
var workBook = excelApp.Workbooks.Open(getFilePath(fileName));
var workSheet = (Microsoft.Office.Interop.Excel.Worksheet)workBook.Sheets[worksheet];
var toCopy = workSheet.Range[toCopyRange];
var whereInsert = workSheet.Range[whereInsertRange];
whereInsert.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, toCopy.Cut());
}
}
Edit: You could add a constructor to the class where you pass the file Path and some class variables which reference the file, the worksheet etc etc... In this case, you will have independent objects for each file
Based on your description, you want to copy one column from the csv file and paste in the new excel file.
First, I convert the csv file to datatable.
Second, I select the specific column and convert one column to datatable.
Third, I convert the datatable to the new excel file.
You can try the following code.
using System;
using System.Data;
using Excel = Microsoft.Office.Interop.Excel;
class Program
{
static void Main(string[] args)
{
string path = "D:\\t.csv";
DataTable table = ReadCsv(path);
table= new DataView(table).ToTable(false, "Tests");
ExportToExcel(table, "D:\\t.xlsx");
}
public static DataTable ReadCsv(string path)
{
Microsoft.Office.Interop.Excel.Application objXL = null;
Microsoft.Office.Interop.Excel.Workbook objWB = null;
objXL = new Microsoft.Office.Interop.Excel.Application();
objWB = objXL.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Worksheet objSHT = objWB.Worksheets[1];
int rows = objSHT.UsedRange.Rows.Count;
int cols = objSHT.UsedRange.Columns.Count;
DataTable dt = new DataTable();
int noofrow = 1;
for (int c = 1; c <= cols; c++)
{
string colname = objSHT.Cells[1, c].Text;
dt.Columns.Add(colname);
noofrow = 2;
}
for (int r = noofrow; r <= rows; r++)
{
DataRow dr = dt.NewRow();
for (int c = 1; c <= cols; c++)
{
dr[c - 1] = objSHT.Cells[r, c].Text;
}
dt.Rows.Add(dr);
}
objWB.Close();
objXL.Quit();
return dt;
}
public static void ExportToExcel( DataTable tbl, string excelFilePath = null)
{
try
{
if (tbl == null || tbl.Columns.Count == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
var excelApp = new Excel.Application();
excelApp.Workbooks.Add();
// single worksheet
Excel._Worksheet workSheet = excelApp.ActiveSheet;
// column headings
for (var i = 0; i < tbl.Columns.Count; i++)
{
workSheet.Cells[1, i + 1] = tbl.Columns[i].ColumnName;
}
// rows
for (var i = 0; i < tbl.Rows.Count; i++)
{
// to do: format datetime values before printing
for (var j = 0; j < tbl.Columns.Count; j++)
{
workSheet.Cells[i + 2, j + 1] = tbl.Rows[i][j];
}
}
// check file path
if (!string.IsNullOrEmpty(excelFilePath))
{
try
{
workSheet.SaveAs(excelFilePath);
excelApp.Quit();
Console.WriteLine("Excel file saved!");
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
+ ex.Message);
}
}
else
{ // no file path is given
excelApp.Visible = true;
}
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: \n" + ex.Message);
}
}
}
Initial csv file.
The excel file:
Edit
Based on the replies below, the error I am experiencing may or may not be causing my inability to read my excel file. That is, I am not getting data from the line worksheet.Cells[row,col].Value in my for loop given below.
Problem
I am trying to return a DataTable with information from an excel file. Specifically, it is an xlsx file from 2013 excel I believe. Please see the code below:
private DataTable ImportToDataTable(string Path)
{
DataTable dt = new DataTable();
FileInfo fi = new FileInfo(Path);
if(!fi.Exists)
{
throw new Exception("File " + Path + " Does not exist.");
}
using (ExcelPackage xlPackage = new ExcelPackage(fi))
{
//Get the worksheet in the workbook
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets.First();
//Obtain the worksheet size
ExcelCellAddress startCell = worksheet.Dimension.Start;
ExcelCellAddress endCell = worksheet.Dimension.End;
//Create the data column
for(int col = startCell.Column; col <= endCell.Column; col++)
{
dt.Columns.Add(col.ToString());
}
for(int row = startCell.Row; row <= endCell.Row; row++)
{
DataRow dr = dt.NewRow(); //Create a row
int i = 0;
for(int col = startCell.Column; col <= endCell.Column; col++)
{
dr[i++] = worksheet.Cells[row, col].Value.ToString();
}
dt.Rows.Add(dr);
}
}
return dt;
}
Error
This is where things get weird. I can see the proper value in startCell and endCell. However, when I look at worksheet I take a peek under Cells and I see something I don't understand:
worksheet.Cells.Current' threw an exception of type 'System.NullReferenceException
Attempts
Reformatting my excel with general fields.
Making sure no field in my excel was empty
RTFM'ed epplus documentation. Nothing suggestive of this error.
Looked at EPPlus errors on stackoverflow. My problem is unique.
Honestly, I am having trouble figuring out what this error is really saying? Is something wrong with my format? Is something wrong with epplus? I have read on here people had no problems with 2013 xlsx with eeplus and I am only trying to parse the excel file by row. If someone could help me shed light on what this error means and how to rectify it. I would be most grateful. I've spent quite a long time trying to figure this out.
When we give:
dr[i++] = worksheet.Cells[row, col].Value.ToString();
it search for value at that column, if the column is empty, it gives Null reference error.
Try instead:
dr[i++] = worksheet.Cells[row, col].Text;
Hope this will help
Like #Thorians said, current is really meant to use when you enumerating the cells. If you want to use it in purest form and actually be able to call current then you would need something like this:
using (var pck = new ExcelPackage(existingFile))
{
var worksheet = pck.Workbook.Worksheets.First();
//this is important to hold onto the range reference
var cells = worksheet.Cells;
//this is important to start the cellEnum object (the Enumerator)
cells.Reset();
//Can now loop the enumerator
while (cells.MoveNext())
{
//Current can now be used thanks to MoveNext
Console.WriteLine("Cell [{0}, {1}] = {2}"
, cells.Current.Start.Row
, cells.Current.Start.Column
, cells.Current.Value);
}
}
Note that you have to create a kind of local collection cells for this to work properly. Otherwise Current will be null if you tried `worksheet.cells.current'
But it would be simpler to use a ForEach and have the CLR do the work for you.
UPDATE: Based on comments. Your code should work fine as is, could it be your excel file:
[TestMethod]
public void Current_Cell_Test()
{
//http://stackoverflow.com/questions/32516676/trying-to-read-excel-file-with-epplus-and-getting-system-nullexception-error
//Throw in some data
var datatable = new DataTable("tblData");
datatable.Columns.AddRange(new[] { new DataColumn("Col1", typeof (int)), new DataColumn("Col2", typeof (int)),new DataColumn("Col3", typeof (object)) });
for (var i = 0; i < 10; i++)
{
var row = datatable.NewRow(); row[0] = i; row[1] = i * 10; row[2] = Path.GetRandomFileName(); datatable.Rows.Add(row);
}
//Create a test file
var fi = new FileInfo(#"c:\temp\test1.xlsx");
if (fi.Exists)
fi.Delete();
using (var pck = new ExcelPackage(fi))
{
var worksheet = pck.Workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromDataTable(datatable, true);
pck.Save();
}
var dt = new DataTable();
using (ExcelPackage xlPackage = new ExcelPackage(fi))
{
//Get the worksheet in the workbook
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets.First();
//Obtain the worksheet size
ExcelCellAddress startCell = worksheet.Dimension.Start;
ExcelCellAddress endCell = worksheet.Dimension.End;
//Create the data column
for (int col = startCell.Column; col <= endCell.Column; col++)
{
dt.Columns.Add(col.ToString());
}
for (int row = startCell.Row; row <= endCell.Row; row++)
{
DataRow dr = dt.NewRow(); //Create a row
int i = 0;
for (int col = startCell.Column; col <= endCell.Column; col++)
{
dr[i++] = worksheet.Cells[row, col].Value.ToString();
}
dt.Rows.Add(dr);
}
}
Console.Write("{{dt Rows: {0} Columns: {1}}}", dt.Rows.Count, dt.Columns.Count);
}
Give this in the output:
{Rows: 11, Columns: 3}
Current is the current range when enumerating.
there is nothing wrong with this throwing an exception in debugging inspection when it is not being used within an enumerating scope.
code sample:
var range = ws.Cells[1,1,1,100];
foreach (var cell in range)
{
var a = range.Current.Value; // a is same as b
var b = cell.Value;
}
I am also getting same issue while reading excel file and none of the solution provided worked for me. Here is working code:
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());
}
}
}
}
I am developing an application that should extract excel data in a Gridview and show the details of individual data in a Detailsview. There is no use of SQL Server and sqlDataSource here. I am in dilemma though.
protected void btnViewDetail_Click(object sender, EventArgs e)
{
{
// What to write in here?
}
}
I have a button named 'View Detail' in GridView that should redirect me to Detailsview with the details of selected data.
Thanks.
Use this method for exporting datagridview to excel
parameters -> excel path, and grid name
public void exportExcel(string path, DataGridView dgv)
{
try
{
Microsoft.Office.Interop.Excel._Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
ExcelApp.Application.Workbooks.Add(Type.Missing);
ExcelApp.Columns.ColumnWidth = 10;
for (int j = 0; j < dgv.ColumnCount; j++)
{
ExcelApp.Cells[1, j + 1] = dgv.Columns[j].HeaderText;
}
Microsoft.Office.Interop.Excel.Range headerColumnRange = ExcelApp.get_Range("A1", "Z1");
headerColumnRange.Font.Bold = true;
headerColumnRange.Font.Color = 0xFF0000;
for (int i = 1; i < dgv.Rows.Count; i++)
{
//DataGridViewRow row = dataGridView1.Rows[i];
for (int j = 0; j < dgv.ColumnCount; j++)
{
ExcelApp.Cells[i + 1, j + 1] = dgv.Rows[i - 1].Cells[j].Value.ToString();
}
}
ExcelApp.ActiveWorkbook.SaveCopyAs(path);
ExcelApp.ActiveWorkbook.Saved = true;
ExcelApp.Quit();
}
catch { }
}
You can use EasyXLS Excel library to extract data from the Excel file. The Excel can be imported into a DataSet and no SQL Server is required.
// Create an instance of the class that imports Excel files
ExcelDocument xls = new ExcelDocument();
// Import Excel file to DataTable
DataSet ds = xls.easy_ReadXLSXActiveSheet_AsDataSet("Excel.xlsx");
DataTable dataTable = ds.Tables[0];
// Set the GridView data
gridView.DataSource = dataTable;
If you have more than one sheet into your Excel file, you may check for more details on import Excel to Dataset in C#.
I know that there are different ways to read an Excel file:
Iterop
Oledb
Open Xml SDK
Compatibility is not a question because the program will be executed in a controlled environment.
My Requirement :
Read a file to a DataTable / CUstom Entities (I don't know how to make dynamic properties/fields to an object[column names will be variating in an Excel file])
Use DataTable/Custom Entities to perform some operations using its data.
Update DataTable with the results of the operations
Write it back to excel file.
Which would be simpler.
Also if possible advice me on custom Entities (adding properties/fields to an object dynamically)
Take a look at Linq-to-Excel. It's pretty neat.
var book = new LinqToExcel.ExcelQueryFactory(#"File.xlsx");
var query =
from row in book.Worksheet("Stock Entry")
let item = new
{
Code = row["Code"].Cast<string>(),
Supplier = row["Supplier"].Cast<string>(),
Ref = row["Ref"].Cast<string>(),
}
where item.Supplier == "Walmart"
select item;
It also allows for strongly-typed row access too.
I realize this question was asked nearly 7 years ago but it's still a top Google search result for certain keywords regarding importing excel data with C#, so I wanted to provide an alternative based on some recent tech developments.
Importing Excel data has become such a common task to my everyday duties, that I've streamlined the process and documented the method on my blog: best way to read excel file in c#.
I use NPOI because it can read/write Excel files without Microsoft Office installed and it doesn't use COM+ or any interops. That means it can work in the cloud!
But the real magic comes from pairing up with NPOI Mapper from Donny Tian because it allows me to map the Excel columns to properties in my C# classes without writing any code. It's beautiful.
Here is the basic idea:
I create a .net class that matches/maps the Excel columns I'm interested in:
class CustomExcelFormat
{
[Column("District")]
public int District { get; set; }
[Column("DM")]
public string FullName { get; set; }
[Column("Email Address")]
public string EmailAddress { get; set; }
[Column("Username")]
public string Username { get; set; }
public string FirstName
{
get
{
return Username.Split('.')[0];
}
}
public string LastName
{
get
{
return Username.Split('.')[1];
}
}
}
Notice, it allows me to map based on column name if I want to!
Then when I process the excel file all I need to do is something like this:
public void Execute(string localPath, int sheetIndex)
{
IWorkbook workbook;
using (FileStream file = new FileStream(localPath, FileMode.Open, FileAccess.Read))
{
workbook = WorkbookFactory.Create(file);
}
var importer = new Mapper(workbook);
var items = importer.Take<CustomExcelFormat>(sheetIndex);
foreach(var item in items)
{
var row = item.Value;
if (string.IsNullOrEmpty(row.EmailAddress))
continue;
UpdateUser(row);
}
DataContext.SaveChanges();
}
Now, admittedly, my code does not modify the Excel file itself. I am instead saving the data to a database using Entity Framework (that's why you see "UpdateUser" and "SaveChanges" in my example). But there is already a good discussion on SO about how to save/modify a file using NPOI.
Using OLE Query, it's quite simple (e.g. sheetName is Sheet1):
DataTable LoadWorksheetInDataTable(string fileName, string sheetName)
{
DataTable sheetData = new DataTable();
using (OleDbConnection conn = this.returnConnection(fileName))
{
conn.Open();
// retrieve the data using data adapter
OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [" + sheetName + "$]", conn);
sheetAdapter.Fill(sheetData);
conn.Close();
}
return sheetData;
}
private OleDbConnection returnConnection(string fileName)
{
return new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + "; Jet OLEDB:Engine Type=5;Extended Properties=\"Excel 8.0;\"");
}
For newer Excel versions:
return new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties=Excel 12.0;");
You can also use Excel Data Reader an open source project on CodePlex. Its works really well to export data from Excel sheets.
The sample code given on the link specified:
FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read);
//1. Reading from a binary Excel file ('97-2003 format; *.xls)
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
//...
//2. Reading from a OpenXml Excel file (2007 format; *.xlsx)
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
//...
//3. DataSet - The result of each spreadsheet will be created in the result.Tables
DataSet result = excelReader.AsDataSet();
//...
//4. DataSet - Create column names from first row
excelReader.IsFirstRowAsColumnNames = true;
DataSet result = excelReader.AsDataSet();
//5. Data Reader methods
while (excelReader.Read())
{
//excelReader.GetInt32(0);
}
//6. Free resources (IExcelDataReader is IDisposable)
excelReader.Close();
Reference: How do I import from Excel to a DataSet using Microsoft.Office.Interop.Excel?
Try to use this free way to this, https://freenetexcel.codeplex.com
Workbook workbook = new Workbook();
workbook.LoadFromFile(#"..\..\parts.xls",ExcelVersion.Version97to2003);
//Initialize worksheet
Worksheet sheet = workbook.Worksheets[0];
DataTable dataTable = sheet.ExportDataTable();
If you can restrict it to just (Open Office XML format) *.xlsx files, then probably the most popular library would be EPPLus.
Bonus is, there are no other dependencies. Just install using nuget:
Install-Package EPPlus
Try to use Aspose.cells library (not free, but trial is enough to read), it is quite good
Install-package Aspose.cells
There is sample code:
using Aspose.Cells;
using System;
namespace ExcelReader
{
class Program
{
static void Main(string[] args)
{
// Replace path for your file
readXLS(#"C:\MyExcelFile.xls"); // or "*.xlsx"
Console.ReadKey();
}
public static void readXLS(string PathToMyExcel)
{
//Open your template file.
Workbook wb = new Workbook(PathToMyExcel);
//Get the first worksheet.
Worksheet worksheet = wb.Worksheets[0];
//Get cells
Cells cells = worksheet.Cells;
// Get row and column count
int rowCount = cells.MaxDataRow;
int columnCount = cells.MaxDataColumn;
// Current cell value
string strCell = "";
Console.WriteLine(String.Format("rowCount={0}, columnCount={1}", rowCount, columnCount));
for (int row = 0; row <= rowCount; row++) // Numeration starts from 0 to MaxDataRow
{
for (int column = 0; column <= columnCount; column++) // Numeration starts from 0 to MaxDataColumn
{
strCell = "";
strCell = Convert.ToString(cells[row, column].Value);
if (String.IsNullOrEmpty(strCell))
{
continue;
}
else
{
// Do your staff here
Console.WriteLine(strCell);
}
}
}
}
}
}
Read from excel, modify and write back
/// <summary>
/// /Reads an excel file and converts it into dataset with each sheet as each table of the dataset
/// </summary>
/// <param name="filename"></param>
/// <param name="headers">If set to true the first row will be considered as headers</param>
/// <returns></returns>
public DataSet Import(string filename, bool headers = true)
{
var _xl = new Excel.Application();
var wb = _xl.Workbooks.Open(filename);
var sheets = wb.Sheets;
DataSet dataSet = null;
if (sheets != null && sheets.Count != 0)
{
dataSet = new DataSet();
foreach (var item in sheets)
{
var sheet = (Excel.Worksheet)item;
DataTable dt = null;
if (sheet != null)
{
dt = new DataTable();
var ColumnCount = ((Excel.Range)sheet.UsedRange.Rows[1, Type.Missing]).Columns.Count;
var rowCount = ((Excel.Range)sheet.UsedRange.Columns[1, Type.Missing]).Rows.Count;
for (int j = 0; j < ColumnCount; j++)
{
var cell = (Excel.Range)sheet.Cells[1, j + 1];
var column = new DataColumn(headers ? cell.Value : string.Empty);
dt.Columns.Add(column);
}
for (int i = 0; i < rowCount; i++)
{
var r = dt.NewRow();
for (int j = 0; j < ColumnCount; j++)
{
var cell = (Excel.Range)sheet.Cells[i + 1 + (headers ? 1 : 0), j + 1];
r[j] = cell.Value;
}
dt.Rows.Add(r);
}
}
dataSet.Tables.Add(dt);
}
}
_xl.Quit();
return dataSet;
}
public string Export(DataTable dt, bool headers = false)
{
var wb = _xl.Workbooks.Add();
var sheet = (Excel.Worksheet)wb.ActiveSheet;
//process columns
for (int i = 0; i < dt.Columns.Count; i++)
{
var col = dt.Columns[i];
//added columns to the top of sheet
var currentCell = (Excel.Range)sheet.Cells[1, i + 1];
currentCell.Value = col.ToString();
currentCell.Font.Bold = true;
//process rows
for (int j = 0; j < dt.Rows.Count; j++)
{
var row = dt.Rows[j];
//added rows to sheet
var cell = (Excel.Range)sheet.Cells[j + 1 + 1, i + 1];
cell.Value = row[i];
}
currentCell.EntireColumn.AutoFit();
}
var fileName="{somepath/somefile.xlsx}";
wb.SaveCopyAs(fileName);
_xl.Quit();
return fileName;
}
I used Office's NuGet Package: DocumentFormat.OpenXml and pieced together the code from that component's doc site.
With the below helper code, was similar in complexity to my other CSV file format parsing in that project...
public static async Task ImportXLSX(Stream stream, string sheetName) {
{
// This was necessary for my Blazor project, which used a BrowserFileStream object
MemoryStream ms = new MemoryStream();
await stream.CopyToAsync(ms);
using (var document = SpreadsheetDocument.Open(ms, false))
{
// Retrieve a reference to the workbook part.
WorkbookPart wbPart = document.WorkbookPart;
// Find the sheet with the supplied name, and then use that
// Sheet object to retrieve a reference to the first worksheet.
Sheet theSheet = wbPart?.Workbook.Descendants<Sheet>().Where(s => s?.Name == sheetName).FirstOrDefault();
// Throw an exception if there is no sheet.
if (theSheet == null)
{
throw new ArgumentException("sheetName");
}
WorksheetPart wsPart = (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
// For shared strings, look up the value in the
// shared strings table.
var stringTable =
wbPart.GetPartsOfType<SharedStringTablePart>()
.FirstOrDefault();
// I needed to grab 4 cells from each row
// Starting at row 11, until the cell in column A is blank
int row = 11;
while (true) {
var accountNameCell = GetCell(wsPart, "A" + row.ToString());
var accountName = GetValue(accountNameCell, stringTable);
if (string.IsNullOrEmpty(accountName)) {
break;
}
var investmentNameCell = GetCell(wsPart, "B" + row.ToString());
var investmentName = GetValue(investmentNameCell, stringTable);
var symbolCell = GetCell(wsPart, "D" + row.ToString());
var symbol = GetValue(symbolCell, stringTable);
var marketValue = GetCell(wsPart, "J" + row.ToString()).InnerText;
// DO STUFF with data
row++;
}
}
}
private static string? GetValue(Cell cell, SharedStringTablePart stringTable) {
try {
return stringTable.SharedStringTable.ElementAt(int.Parse(cell.InnerText)).InnerText;
} catch (Exception) {
return null;
}
}
private static Cell GetCell(WorksheetPart wsPart, string cellReference) {
return wsPart.Worksheet.Descendants<Cell>().Where(c => c.CellReference.Value == cellReference)?.FirstOrDefault();
}
Right this is starting to drive me mad, I have a asp:gridview with check boxes, the user has the ability to check which information he/she wants to export to excel, when they click the button the below code is executed, now you can see im doing a for each row in the gridview etc
if the check box for a row is checked i go to the DB execute some information return a datatable and then try and add its values to the Epplus excel spreadsheet, but in the foreach(datacolum) and foreach(DataRow) it doesnt allow me to use
ws.Cells[1, iColumnCount] = c.ColumnName; as it says its read only?
but this one excel spread sheet could have 1 - 10 different bits of information depending on how many checkboxes are checked....can someone please help me and put me out of my misery........ :(
heres my full code
protected void BtnTest_Click(object sender, EventArgs e)
{
bool ReportGenerated = false;
FileInfo newFile = new FileInfo("C:\\Users\\Scott.Atkinson\\Desktop\\book1.xls");
ExcelPackage pck = new ExcelPackage(newFile);
foreach (GridViewRow row in gvPerformanceResult.Rows)
{
object misValue = System.Reflection.Missing.Value;
CheckBox chkExcel = (CheckBox)row.FindControl("chkExportToExcel");
if (chkExcel.Checked)
{
HyperLink HypCreatedBy = (HyperLink)row.FindControl("HyperCreatedBy"); //Find the name of Sales agent
string CreatedBy = HypCreatedBy.Text;
string Fname = HypCreatedBy.Text;
string[] names = Fname.Split();
CreatedBy = names[0];
CreatedBy = CreatedBy + "." + names[1];
WebUser objUser = new WebUser(CreatedBy, true);
DataTable DT = new DataTable();
LeadOpportunities objLeadOpportunities = new LeadOpportunities();
DT = objLeadOpportunities.LoadPRCDetail("PRC", objUser.ShortAbbr, objUser.CanViewAllLead, ReportCriteria); // Load the information to export to Excel.
if (DT.Rows.Count > 0)
{
ReportGenerated = true;
//Add the Content sheet
var ws = pck.Workbook.Worksheets.Add("Content");
ws.View.ShowGridLines = true;
int iRowCount = ws.Dimension.Start.Row; //Counts how many rows have been used in the Excel Spreadsheet
int iColumnCount = ws.Dimension.Start.Column; //Counts how many Columns have been used.
if (iRowCount > 1)
iRowCount = iRowCount + 2;
else
iRowCount = 1;
iColumnCount = 0;
foreach (DataColumn c in DT.Columns)
{
iColumnCount++;
if (iRowCount == 0)
ws.Cells[1, iColumnCount] = c.ColumnName;
else
ws.Cells[iRowCount, iColumnCount] = c.ColumnName;
}
foreach (DataRow r in DT.Rows)
{
iRowCount++;
iColumnCount = 0;
foreach (DataColumn c in DT.Columns)
{
iColumnCount++;
if (iRowCount == 1)
ws.Cells[iRowCount + 1, iColumnCount] = r[c.ColumnName].ToString();
else
ws.Cells[iRowCount, iColumnCount] = r[c.ColumnName].ToString();
WorkSheet.Columns.AutoFit(); //Correct the width of the columns
}
}
pck.Save();
System.Diagnostics.Process.Start("C:\\Users\\Scott.Atkinson\\Desktop\\book1.xls");
}
}
}
}
Any help would be highly appreciated.
it doesnt allow me to use
ws.Cells[1, iColumnCount] = c.ColumnName;
That line should have been:
ws.Cells[1,iColumnCount].Value = c.ColumnName
but it now falls over on the int iRowCount = ws.Dimension.Start.Row; //Counts how many rows have been used in the Excel Spreadsheet int iColumnCount = ws.Dimension.Start.Column; //Counts how many Columns have been used. can someone help me get the row/column count?
The .Dimension property gives the address for the range covering the top left cell to the bottom right cell so to get the row count we can use:
var rowCount = ws.Dimension.End.Row - ws.Dimension.Start.Row + 1;
and similarly for the column count:
var colCount = ws.Dimension.End.Column - ws.Dimension.Start.Column + 1;