I'm trying to get the name of the first sheet of an excel workbook.
Instead of getting the sheets name in the order as it appears in the Excel workbook it appears sorted alphabetically.
Does anyone have an idea to get the names not sorted??
private String[] GetExcelSheetNames(string excelFile)
{
OleDbConnection objConn = null;
System.Data.DataTable dt = null;
try
{
// Connection String. Change the excel file to the file you
// will search.
String connString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + excelFile + ";Extended Properties=Excel 8.0;";
// Create connection object by using the preceding connection string.
objConn = new OleDbConnection(connString);
// Open connection with the database.
objConn.Open();
// Get the data table containg the schema guid.
dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if(dt == null)
{
return null;
}
String[] excelSheets = new String[dt.Rows.Count];
int i = 0;
// Add the sheet name to the string array.
foreach(DataRow row in dt.Rows)
{
excelSheets[i] = row["TABLE_NAME"].ToString();
i++;
}
// Loop through all of the sheets if you want too...
for(int j=0; j < excelSheets.Length; j++)
{
// Query each excel sheet.
}
return excelSheets;
}
catch(Exception ex)
{
return null;
}
finally
{
// Clean up.
if(objConn != null)
{
objConn.Close();
objConn.Dispose();
}
if(dt != null)
{
dt.Dispose();
}
}
}
I already get a solution with my question.
//get sheet number 1 name
var excelFile = Path.GetFullPath(llFileName);
var excel = new Excel.Application();
var workbook = excel.Workbooks.Open(llFileName);
var sheet = (Excel.Worksheet)workbook.Worksheets.Item[1]; // 1 is the first item, this is NOT a zero-based collection
string sheetName = sheet.Name;
Hope it help for the other
Related
I am looking for some assistance in obtaining the Columns from a specific worksheet using C#. I am currently able to connect to the Excel file and obtain a read of the Columns, but it is giving me the Columns for every worksheet in my Excel, not a specific one.
What can I do to my code to obtain only the Columns from the desired worksheet? Here is my code which currently fills my Checkbox List with all of the columns.
OleDbConnection excelConnection = new OleDbConnection(String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0\"", strFullPath));
using (OleDbCommand cmd = new OleDbCommand("SELECT * FROM [LogFile$]", excelConnection))
{
excelConnection.Open();
DataTable dt = excelConnection.GetSchema("Columns");
cbColumnList.DataSource = dt;
cbColumnList.DataTextField = "Column_name";
cbColumnList.DataValueField = "Column_name";
cbColumnList.DataBind();
}
I am fairely sure my issue has something to do with where I am creating hte DataTable, as i'm pulling the Scheme from excelConnection and not cmd, thus it's most likely bypassing my query where I have defined the Worksheet to get the columns from. If this is the case, how would I fix it?
First Solution
using System;
using System.Data;
using System.Data.OleDb;
namespace ConsoleApp35
{
class Program
{
static void Main(string[] args)
{
using (OleDbConnection excelConnection = new OleDbConnection(String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0\"", #"D:\Coverage.xlsx")))
{
excelConnection.Open();
var dt = new DataTable();
var da = new OleDbDataAdapter();
var _command = new OleDbCommand();
_command.Connection = excelConnection;
_command.CommandText = "SELECT * FROM [Sheet1$]";
da.SelectCommand = _command;
try
{
da.Fill(dt);
// printing columns names
foreach (DataColumn d in dt.Columns)
{
Console.WriteLine(d.ColumnName);
}
// dt has all data from Sheet1
foreach (DataRow r in dt.Rows)
{
Console.WriteLine(String.Join(", ", r.ItemArray));
}
}
catch (Exception e)
{
// process error here
}
Console.ReadLine();
}
}
}
}
Second solution
This solution is for those who have the same requirements but use Open XML.
Install both Open XML packages from Microsoft:
https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=5124
In your solution add a references to DocumentFormat.OpenXml and WindowsBase assemblies. Add the following using directives:
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Packaging;
using System.Text.RegularExpressions;
Add the following methods to your class that processes your Excel file.
private static string GetColumnName(string cellName)
{
var regex = new Regex("[a-zA-Z]+");
var match = regex.Match(cellName);
return match.Value;
}
public static SharedStringItem GetSharedStringItemById(WorkbookPart
workbookPart, int id)
{
return workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem> ().ElementAt(id);
}
Use the following code to get columns names from the specified sheet. Also, additionally, you can process here all the data you need from the file. I have tested reading data from a simple Excel sheet that contains 2 columns and several rows where cells have integer and string values. For processing other data types you need to add additional blocks of code checking cell.DataType.
var columnsNames = new HashSet<string>();
var data = new List<List<string>>();
using (SpreadsheetDocument myDoc =
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(#"D:\FileName.xlsx",
false))
{
foreach (Sheet s in myDoc.WorkbookPart.Workbook.Sheets)
{
if (s.Name == "Sheet1") {
string relationshipId = s.Id.Value;
WorksheetPart worksheetPart = (WorksheetPart)myDoc.WorkbookPart.GetPartById(relationshipId);
var sd = worksheetPart.Worksheet.Elements<SheetData>().First();
IEnumerable<Row> rows = sd.Elements<Row>();
foreach (Row row in rows)
{
var rowList = new List<string>();
foreach (Cell cell in row.Elements<Cell>())
{
// get columns names
var columnName = GetColumnName(cell.CellReference.Value);
columnsNames.Add(columnName);
// process data
string cellValue = string.Empty;
if (cell.DataType != null)
{
if (cell.DataType == CellValues.SharedString)
{
int id = -1;
if (Int32.TryParse(cell.InnerText, out id))
{
SharedStringItem item = GetSharedStringItemById(myDoc.WorkbookPart, id);
if (item.Text != null)
{
cellValue = item.Text.Text;
}
else if (item.InnerText != null)
{
cellValue = item.InnerText;
}
else if (item.InnerXml != null)
{
cellValue = item.InnerXml;
}
}
}
}
else
{
cellValue = cell.CellValue.Text;
}
rowList.Add(cellValue);
}
data.Add(rowList);
}
}
}
myDoc.Close();
}
I am creating a winform application where every day, a user will select a xlsx file with the day's shipping information to be merged with our invoicing data.
The challenge I am having is when the user does not download the xlsx file with the specification that the winform data requires. (I wish I could eliminate this step with an API connection but sadly I cannot)
My first step is checking to see if the xlsx file has headers to that my file path is valid
Example
string connString = "provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + *path* + "';Extended Properties='Excel 12.0;HDR=YES;';";
Where path is returned from an OpenFileDialog box
If the file was chosen wasn't downloaded with headers the statement above throws an exception.
If change HDR=YES; to HDR=NO; then I have trouble identifying the columns I need and if the User bothered to include the correct ones.
My code then tries to load the data into a DataTable
private void loadRows()
{
for (int i = 0; i < deliveryTable.Rows.Count; i++)
{
DataRow dr = deliveryTable.Rows[i];
int deliveryId = 0;
bool result = int.TryParse(dr[0].ToString(), out deliveryId);
if (deliveryId > 1 && !Deliveries.ContainsKey(deliveryId))
{
var delivery = new Delivery(deliveryId)
{
SalesOrg = Convert.ToInt32(dr[8]),
SoldTo = Convert.ToInt32(dr[9]),
SoldName = dr[10].ToString(),
ShipTo = Convert.ToInt32(dr[11]),
ShipName = dr[12].ToString(),
};
Which all works only if the columns are in the right place.
If they are not in the right place my thought is to display a message to the user to get the right information
Does anyone have any suggestions?
(Sorry, first time posting a question and still learning to think through it)
I guess you're loading the spreadsheet into a Datatable? Hard to tell with one line of code. I would use the columns collection in the datatable and check to see if all the columns you want are there. Sample code to enumerate the columns below.
private void PrintValues(DataTable table)
{
foreach(DataRow row in table.Rows)
{
foreach(DataColumn column in table.Columns)
{
Console.WriteLine(row[column]);
}
}
}
private void GetExcelSheetForUpload(string PathName, string UploadExcelName)
{
string excelFile = "DateExcel/" + PathName;
OleDbConnection objConn = null;
System.Data.DataTable dt = null;
try
{
DataSet dss = new DataSet();
String connString = "Provider=Microsoft.ACE.OLEDB.12.0;Persist Security Info=True;Extended Properties=Excel 12.0 Xml;Data Source=" + PathName;
objConn = new OleDbConnection(connString);
objConn.Open();
dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return;
}
String[] excelSheets = new String[dt.Rows.Count];
int i = 0;
foreach (DataRow row in dt.Rows)
{
if (i == 0)
{
excelSheets[i] = row["TABLE_NAME"].ToString();
OleDbCommand cmd = new OleDbCommand("SELECT * FROM [" + excelSheets[i] + "]", objConn);
OleDbDataAdapter oleda = new OleDbDataAdapter();
oleda.SelectCommand = cmd;
oleda.Fill(dss, "TABLE");
}
i++;
}
grdExcel.DataSource = dss.Tables[0].DefaultView;
grdExcel.DataBind();
lblTotalRec.InnerText = Convert.ToString(grdExcel.Rows.Count);
}
catch (Exception ex)
{
ViewState["Fuletypeidlist"] = "0";
grdExcel.DataSource = null;
grdExcel.DataBind();
}
finally
{
if (objConn != null)
{
objConn.Close();
objConn.Dispose();
}
if (dt != null)
{
dt.Dispose();
}
}
}
if (grdExcel.HeaderRow.Cells[0].Text.ToString() == "CODE")
{
GetExcelSheetForEmpl(PathName);
}
else
{
divStatusMsg.Style.Add("display", "");
divStatusMsg.Attributes.Add("class", "alert alert-danger alert-dismissable");
divStatusMsg.InnerText = "ERROR !!... Upload Excel Sheet in header Defined Format ";
}
Using Oledb, is it possible to get all NamedRanges of a particula sheet in Excel?
I have written following code which gives me NamedRanges but I am not able to figure out to which sheet does the NamedRange refer to.
private String[] GetExcelSheetNames(string excelFilePath)
{
OleDbConnection objConn = null;
System.Data.DataTable dt = null;
try
{
//String connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + excelFile + ";Extended Properties=Excel 12.0;";
string connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=Excel 12.0", excelFilePath);
objConn = new OleDbConnection(connectionString);
objConn.Open();
// Get the data table containg the schema guid.
dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables_Info, null);
if (dt == null)
return null;
String[] excelSheets = new String[dt.Rows.Count];
int i = 0;
// Add the sheet name to the string array.
foreach (DataRow row in dt.Rows)
excelSheets[i++] = row["TABLE_NAME"].ToString();
return excelSheets;
}
catch (Exception ex)
{
return null;
}
finally
{
// Clean up.
if (objConn != null)
{
objConn.Close();
objConn.Dispose();
}
if (dt != null)
{
dt.Dispose();
}
}
}
I am a Open XML SDK fan. The solution is straightforward. This returns both workbook and sheet scoped named ranges, on the left there's the Excel name manager definitions, 2 sheets with 2 named ranges in each sheet, on the right a sample run.
MSDN reference.
/// <summary>
/// The procedure examines the workbook that you specify,
/// looking for the part that contains defined names.
/// If it exists, the procedure iterates through all the
/// contents of the part, adding the name and value for
/// each defined name to the returned dictionary
/// </summary>
public static IDictionary<String, String> XLGetDefinedNames(String fileName)
{
var returnValue = new Dictionary<String, String>();
//
using (SpreadsheetDocument document =
SpreadsheetDocument.Open(fileName, false))
{
var wbPart = document.WorkbookPart;
//
DefinedNames definedNames = wbPart.Workbook.DefinedNames;
if (definedNames != null)
{
foreach (DefinedName dn in definedNames)
returnValue.Add(dn.Name.Value, dn.Text);
}
}
//
return returnValue;
}
I'm getting excel sheet name but just the sheet that has data.
String fpath = "Provider=Microsoft.ACE.OLEDB.12.0; data source=" +tbpath.Text+ ";Extended Properties='Excel 12.0 Xml;HDR=YES';";
file = new OleDbConnection(fpath);
file.Open();
dt = file.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
//return null;
}
cbsheet.Enabled = true;
//String[] excelSheets = new String[dt.Rows.Count];
//int i = 0;
// Add the sheet name to the string array.
foreach (DataRow row in dt.Rows)
{
if (row["TABLE_NAME"].ToString().Contains("$") )//checks whether row contains '_xlnm#_FilterDatabase' or sheet name(i.e. sheet name always ends with $ sign)
{
cbsheet.Items.Add(row["TABLE_NAME"].ToString());
}
}
//return excelSheets;
}
catch (Exception ex)
{
MessageBox.Show("ERROR: "+ex);
}
You could check each sheet for rows i.e.
try
{
foreach (DataRow row in dt.Rows)
{
if (row["TABLE_NAME"].ToString().Contains("$") )
{
OleDbCommand cmd = new OleDbCommand(
"select * from [" + row["TABLE_NAME"].ToString() + "]", file);
using (DbDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
cbsheet.Items.Add(row["TABLE_NAME"].ToString());
}
dr.close();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("ERROR: "+ex);
}
You can just exclude them from getting added.
I used this code to filter out empty sheets. Turns out
they are sheets that shouldn't be accessed by the user.
You can solve this problem in 2 ways.
a. Ignore them
b. Drop down the sheets.
I would highly suggest going with the former.
Use this code;
if (!dt.Rows[i]["Table_Name"].ToString().Contains("FilterDatabase") && !dt.Rows[i]["Table_Name"].ToString().EndsWith("$'"))
{
}
I am using IExcelDataReader to reader to read a excel sheet using following code:
private static IExcelDataReader FetchDataReaderForExcel(HttpPostedFile file)
{
IExcelDataReader dataReader = null;
if (null != file)
{
string fileExtension = Path.GetExtension(file.FileName);
switch (fileExtension)
{
case ".xls":
dataReader = ExcelReaderFactory.CreateBinaryReader(file.InputStream);
break;
case ".xlsx":
dataReader = ExcelReaderFactory.CreateOpenXmlReader(file.InputStream);
break;
default:
dataReader = null;
break;
}
}
return dataReader;
}
When i am reading the excel sheet using this method sometime i am not able to read the data correctly. Sometime it is not able to read column other time it is not able to read the entire data. I need to format each column to normal text and then upload again, it works then. Excel contains data contains integer, string, datetime, hyperlink. Can anyone tell me what could be the problem or alternative for this?
I'm using oledb and it works perfect for me. Here is my example:
using (OleDbConnection con = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + Filename + ";Extended Properties=\"Excel 12.0 Xml;HDR=YES\""))
{
//
string listName = "Sheet1";
con.Open();
try
{
DataSet ds = new DataSet();
OleDbDataAdapter odb = new OleDbDataAdapter("select * from [" + listName + "$]", con);
odb.Fill(ds);
con.Close();
foreach (DataRow myrow in ds.Tables[0].Rows)
{
Object[] cells = myrow.ItemArray;
if (cells[0].ToString().Length > 0 || cells[1].ToString().Length > 0 || cells[2].ToString().Length > 0)
{
/*
cells[0]
cells[1]
cells[2]
are getting values
*/
}
}
}
catch (Exception ex)
{
return null;
}
}
OLEDB.12.0 works with both .xls and .xlsx
If you are Uploading the file ,and the file has Many sheets in it and you want to read all the sheets you can follow this method....first write the Code for FileUPload and save the uploaded file in a path....using that path you can read the files
/// <summary>
/// This method retrieves the excel sheet names from
/// an excel workbook & reads the excel file
/// </summary>
/// <param name="excelFile">The excel file.</param>
/// <returns></returns>
#region GetsAllTheSheetNames of An Excel File
public static string[] ExcelSheetNames(String excelFile)
{
DataTable dt;
string connString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excelFile + ";Extended Properties='Excel 12.0;HDR=Yes'";
using (OleDbConnection objConn = new OleDbConnection(connString))
{
objConn.Open();
dt =
objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return null;
}
string[] res = new string[dt.Rows.Count];
for (int i = 0; i < res.Length; i++)
{
string name = dt.Rows[i]["TABLE_NAME"].ToString();
if (name[0] == '\'')
{
//numeric sheetnames get single quotes around
//remove them here
if (Regex.IsMatch(name, #"^'\d\w+\$'$"))
{
name = name.Substring(1, name.Length - 2);
}
}
res[i] = name;
}
return res;
}
}
#endregion
//You can read files and store the data in a dataset use them
public static DataTable GetWorksheet(string excelFile,string worksheetName)
{
string connString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excelFile + ";Extended Properties='Excel 12.0;HDR=Yes'";
OleDbConnection con = new System.Data.OleDb.OleDbConnection(connString);
OleDbDataAdapter cmd = new System.Data.OleDb.OleDbDataAdapter("select * from [" + worksheetName + "$]", con);
con.Open();
System.Data.DataSet excelDataSet = new DataSet();
cmd.Fill(excelDataSet);
con.Close();
return excelDataSet.Tables[0];
}
Else U can use this method to read the excel file
Just Add the reference
click on the "AddReference" on solution explorer ,click on com tab and Add this reference
Microsoft.Office.Interop.Excel
And add this namespace in your code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Data;
static void Main(string[] args)
{
string Path = #"C:\samples\SEP DUMPS.xls";
// initialize the Excel Application class
Excel.Application app = new Excel.Application();
//Excel.Worksheet NwSheet;
Excel.Range ShtRange;
// create the workbook object by opening the excel file.
Excel.Workbook workBook = app.Workbooks.Open(Path,0,true,5,"","",true,Excel.XlPlatform.xlWindows,"\t",false,false, 0,true,1,0);
// Get The Active Worksheet Using Sheet Name Or Active Sheet
Excel.Worksheet workSheet = (Excel.Worksheet)workBook.ActiveSheet;
int index = 1;
// that is which cell in the excel you are interesting to read.
object rowIndex = 1;
object colIndex1 = 1;
object colIndex2 = 5;
object colIndex3 = 4;
System.Text.StringBuilder sb = new StringBuilder();
try
{
while (((Excel.Range)workSheet.Cells[rowIndex, colIndex1]).Value2 != null)
{
rowIndex =index;
string firstName = Convert.ToString( ((Excel.Range)workSheet.Cells[rowIndex, colIndex1]).Value2);
string lastName = Convert.ToString(((Excel.Range)workSheet.Cells[rowIndex, colIndex2]).Value2);
string Name = Convert.ToString(((Excel.Range)workSheet.Cells[rowIndex, colIndex3]).Value2);
string line = firstName + "," + lastName + "," + Name;
sb.Append(line); sb.Append(Environment.NewLine);
Console.WriteLine(" {0},{1},{2} ", firstName, lastName,Name);
index++;
}
Writetofile(sb.ToString());
ShtRange = workSheet.UsedRange;
Object[,] s = ShtRange.Value;
}
catch (Exception ex)
{
app.Quit();
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
Hope this helps you..........If u have any doubts Ask me...