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...
Related
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
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;
}
Here's my situation. I'm designing a program that takes Excel files (which may be in csv, xls, or xlsx format) from a remote network drive, processes the data, then outputs and stores the results of that process. The program provides a listbox of filenames that are obtained from the remote network drive folder using the method detailed in the accepted answer here. Once the user selects a filename from the listbox, I want the program to find the file and obtain the information from it to do the data processing. I have tried using this method to read the data from the Excel file while in a threaded security context, but that method just fails without giving any kind of error. It seems to not terminate. Am I going about this the wrong way?
Edit - (Final Notes: I have taken out the OleDbDataAdapter and replaced it with EPPlus handling.)
I was able to scrub sensitive data from the code, so here it is:
protected void GetFile(object principalObj)
{
if (principalObj == null)
{
throw new ArgumentNullException("principalObj");
}
IPrincipal principal = (IPrincipal)principalObj;
Thread.CurrentPrincipal = principal;
WindowsIdentity identity = principal.Identity as WindowsIdentity;
WindowsImpersonationContext impersonationContext = null;
if (identity != null)
{
impersonationContext = identity.Impersonate();
}
try
{
string fileName = string.Format("{0}\\" + Files.SelectedValue, #"RemoteDirectoryHere");
string connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.14.0; data source={0}; Extended Properties=Excel 14.0;", fileName);
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM Sheet1", connectionString);
DataSet ds = new DataSet();
adapter.Fill(ds, "Sheet1");
dataTable = ds.Tables["Sheet1"];
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
}
Additional Edit
Now xlsx files have been added to the mix.
Third Party
Third party solutions are not acceptable in this case (unless they allow unrestricted commercial use).
Attempts - (Final Notes: Ultimately I had to abandon OleDb connections.)
I have tried all of the different connection strings offered, and I have tried them with just one file type at a time. None of the connection strings worked with any of the file types.
Permissions
The User does have access to the file and its directory.
Your connection string might be the issue here. As far as I know, there isn't 1 that can read all xls, csv, and xlsx. I think you're using the XLSX connection string.
When I read xls, i use the following connection string:
#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + sFilePath + ";Extended Properties='Excel 8.0;HDR=YES;IMEX=1;'"
Having said that, I recommend using a 3rd party file reader/parser to read XLS and CSV since, from my experience, OleDbDataAdapter is wonky depending on the types of data that's being read (and how mixed they are within each column).
For XLS, try NPOI https://code.google.com/p/npoi/
For CSV, try http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader
For XLSX, try EPPlus http://epplus.codeplex.com/
I've had great success with the above libraries.
Is it really important that you use an OleDb interface for this? I've always done it with Microsoft.Office.Excel.Interop, to wit:
using System;
using Microsoft.Office.Interop.Excel;
namespace StackOverflowExample
{
class Program
{
static void Main(string[] args)
{
var app = new Application();
var wkbk = app.Workbooks.Open(#"c:\data\foo.xls") as Workbook;
var wksht = wkbk.Sheets[1] as Worksheet; // not zero-based!
for (int row = 1; row <= 100; row++) // not zero-based!
{
Console.WriteLine("This is row #" + row.ToString());
for (int col = 1; col <= 100; col++)
{
Console.WriteLine("This is col #" + col.ToString());
var cell = wksht.Cells[row][col] as Range;
if (cell != null)
{
object val = cell.Value;
if (val != null)
{
Console.WriteLine("The value of the cell is " + val.ToString());
}
}
}
}
}
}
}
As you will be dealing with xlsx extension, you should rather opt for the new connection string.
public static string getConnectionString(string fileName, bool HDRValue, bool WriteExcel)
{
string hdrValue = HDRValue ? "YES" : "NO";
string writeExcel = WriteExcel ? string.Empty : "IMEX=1";
return "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + fileName + ";" + "Extended Properties=\"Excel 12.0 xml;HDR=" + hdrValue + ";" + writeExcel + "\"";
}
Above is the code for getting the connection string. First argument expects the actual path for file location. Second argument will decide whether to consider first row values as column headers or not. Third argument helps decide whether you want to open the connection to create and write the data or simply read the data. To read the data set it to "FALSE"
public static ReadData(string filePath, string sheetName, List<string> fieldsToRead, int startPoint, int endPoint)
{
DataTable dt = new DataTable();
try
{
string ConnectionString = ProcessFile.getConnectionString(filePath, false, false);
using (OleDbConnection cn = new OleDbConnection(ConnectionString))
{
cn.Open();
DataTable dbSchema = cn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dbSchema == null || dbSchema.Rows.Count < 1)
{
throw new Exception("Error: Could not determine the name of the first worksheet.");
}
StringBuilder sb = new StringBuilder();
sb.Append("SELECT *");
sb.Append(" FROM [" + sheetName + fieldsToRead[0].ToUpper() + startPoint + ":" + fieldsToRead[1].ToUpper() + endPoint + "] ");
OleDbDataAdapter da = new OleDbDataAdapter(sb.ToString(), cn);
dt = new DataTable(sheetName);
da.Fill(dt);
if (dt.Rows.Count > 0)
{
foreach (DataRow row in dt.Rows)
{
string i = row[0].ToString();
}
}
cn.Dispose();
return fileDatas;
}
}
catch (Exception)
{
}
}
This is for reading 2007 Excel into dataset
DataSet ds = new DataSet();
try
{
string myConnStr = "";
myConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=MyDataSource;Extended Properties=\"Excel 12.0;HDR=YES\"";
OleDbConnection myConn = new OleDbConnection(myConnStr);
OleDbCommand cmd = new OleDbCommand("select * from [Sheet1$] ", myConn);
OleDbDataAdapter adapter = new OleDbDataAdapter();
adapter.SelectCommand = cmd;
myConn.Open();
adapter.Fill(ds);
myConn.Close();
}
catch
{ }
return ds;
Can anyone suggest me how to read excel files in c# using ado.net in disconnected mode.My excel file is quite large and cant be kept in memory.please suggest a method of loading the data into a dataset.
for now i am reading them by using Excel = Microsoft.Office.Interop.Excel and adding the excel reference(com) and then using objects like range etc.
May be this is what you are looking for
http://exceldatareader.codeplex.com/
Id say connect to it with ADO and treat it like a database:
http://www.connectionstrings.com/excel
Here is an example of the what I am using that might be handy for anyone else wanting to get data from an Excel spreadsheet.
It loads each worksheet into a DataTable within a DataSet.
It assumes that you have your headers going from A1 to x1.
using System;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
public class clsExcelWriter : IDisposable
{
private Excel.Application oExcel;
private Excel._Workbook oBook;
private Excel._Worksheet oSheet;
// Used to store the name of the current file
public string FileName
{
get;
private set;
}
public clsExcelWriter(string filename)
{
// Initialize Excel
oExcel = new Excel.Application();
if (!File.Exists(filename))
{
// Create a new one?
}
else
{
oBook = (Excel._Workbook)oExcel.Workbooks.Open(filename);
oSheet = (Excel._Worksheet)oBook.ActiveSheet;
}
this.FileName = filename;
// Supress any alerts
oExcel.DisplayAlerts = false;
}
private string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
public void Dispose()
{
// Lets make sure we release those COM objects!
if (oExcel != null)
{
Marshal.FinalReleaseComObject(oSheet);
oBook.Close();
Marshal.FinalReleaseComObject(oBook);
oExcel.Quit();
Marshal.FinalReleaseComObject(oExcel);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
public static DataSet OpenFile(string filename)
{
DataSet ds = new DataSet();
using (clsExcelWriter xl = new clsExcelWriter(filename))
{
// Iterate through each worksheet
foreach (Excel._Worksheet sheet in xl.oBook.Worksheets)
{
// Create a new table using the sheets name
DataTable dt = new DataTable(sheet.Name);
// Get the first row (where the headers should be located)
object[,] xlValues = (object[,])sheet.get_Range("A1", xl.GetExcelColumnName(sheet.UsedRange.Columns.Count) + 1).Value;
// Iterate through the values to add new DataColumns to the DataTable
for (int i = 0; i < xlValues.GetLength(1); i++)
{
dt.Columns.Add(new DataColumn(xlValues[1, i + 1].ToString()));
}
// Now get the rest of the rows
xlValues = (object[,])sheet.get_Range("A2", xl.GetExcelColumnName(sheet.UsedRange.Columns.Count) + sheet.UsedRange.Rows.Count).Value;
for (int row = 0; row < xlValues.GetLength(0); row++)
{
DataRow dr = dt.NewRow();
for (int col = 0; col < xlValues.GetLength(1); col++)
{
// xlValues array starts from 1, NOT 0 (just to confuse yee)
dr[dt.Columns[col].ColumnName] = xlValues[row + 1, col + 1];
}
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
}
}
// Your DataSet should now be filled! :)
return ds;
}
}
}
Usage
using System.Data;
using ExcelWriter;
namespace Test
{
class Program
{
static void Main(string[] args)
{
DataSet ds = clsExcelWriter.OpenFile(#"C:\Results.xls");
// Do some fancy stuff with the DataSet! xD
while (true) ;
}
}
}
Here what I use to read data from an Excel sheet:
private DbDataReader ReadExcelSheet(string file, string sheet)
{
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + file + ";Extended Properties=Excel 8.0;";
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb");
DbConnection connection = factory.CreateConnection();
connection.ConnectionString = connStr;
DbCommand command = connection.CreateCommand();
string query = BuildSelectQuery(sheet, names_mapping);//you need column names here
command.CommandText = query;
connection.Open();
DbDataReader dr = command.ExecuteReader();
return dr;
}