I have excel file with several excel tables. I want to read all the data in excel tables for a given excel sheet and copy those to a different excel table.
One excel sheet may have several tables
I have done that through VBA. I want to find a C# code to achieve it.
This is the VBA code I used.
Dim tableObject As ListObject
Dim oLastRow As ListRow
Dim srcRow As Range
Set sheet = ThisWorkbook.Worksheets("Sheet1")
For Each tableObject In sheet.ListObjects
Set srcRow = tableObject.DataBodyRange
Set oLastRow = Worksheets("Sheet2").ListObjects("table1").ListRows.Add
srcRow.Copy
oLastRow.Range.PasteSpecial xlPasteValues
Next
Try to follow this:
public static DataTable exceldata(string filePath)
{
DataTable dtexcel = new DataTable();
bool hasHeaders = false;
string HDR = hasHeaders ? "Yes" : "No";
string strConn;
if (filePath.Substring(filePath.LastIndexOf('.')).ToLower() == ".xlsx")
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=\"Excel 12.0;HDR=" + HDR + ";IMEX=0\"";
else
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=\"Excel 8.0;HDR=" + HDR + ";IMEX=0\"";
OleDbConnection conn = new OleDbConnection(strConn);
conn.Open();
DataTable schemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
//Looping Total Sheet of Xl File
/*foreach (DataRow schemaRow in schemaTable.Rows)
{
}*/
//Looping a first Sheet of Xl File
DataRow schemaRow = schemaTable.Rows[0];
string sheet = schemaRow["TABLE_NAME"].ToString();
if (!sheet.EndsWith("_"))
{
string query = "SELECT * FROM [" + sheet3 + "]";
OleDbDataAdapter daexcel = new OleDbDataAdapter(query, conn);
dtexcel.Locale = CultureInfo.CurrentCulture;
daexcel.Fill(dtexcel);
}
conn.Close();
return dtexcel;
}
You can also use the following part of code to import data from tables inside your excel sheet
static void Main(string[] args)
{
try
{
ReadInData readInData = new ReadInData(#"C:\SC.xlsx", "sc_2014");
IEnumerable<Recipient> recipients = readInData.GetData();
}
catch (Exception ex)
{
if(!(ex is FileNotFoundException || ex is ArgumentException || ex is FileToBeProcessedIsNotInTheCorrectFormatException))
throw;
Console.WriteLine(ex.Message);
}
Console.Write(Press any key to continue...);
Console.ReadKey(true);
}
public static class ReadInData
{
public static IEnumerable<Recipient> GetData(string path, string worksheetName, bool isFirstRowAsColumnNames = true)
{
return new ExcelData(path).GetData(worksheetName, isFirstRowAsColumnNames)
.Select(dataRow => new Recipient()
{
Municipality = dataRow["Municipality"].ToString(),
Sexe = dataRow["Sexe"].ToString(),
LivingArea = dataRow["LivingArea"].ToString()
});
}
}
private static IExcelDataReader GetExcelDataReader(string path, bool isFirstRowAsColumnNames)
{
using (FileStream fileStream = File.Open(path, FileMode.Open, FileAccess.Read))
{
IExcelDataReader dataReader;
if (path.EndsWith(".xls"))
dataReader = ExcelReaderFactory.CreateBinaryReader(fileStream);
else if (path.EndsWith(".xlsx"))
dataReader = ExcelReaderFactory.CreateOpenXmlReader(fileStream);
else
throw new FileToBeProcessedIsNotInTheCorrectFormatException("The file to be processed is not an Excel file");
dataReader.IsFirstRowAsColumnNames = isFirstRowAsColumnNames;
return dataReader;
}
}
private static DataSet GetExcelDataAsDataSet(string path, bool isFirstRowAsColumnNames)
{
return GetExcelDataReader(path, isFirstRowAsColumnNames).AsDataSet();
}
private static DataTable GetExcelWorkSheet(string path, string workSheetName, bool isFirstRowAsColumnNames)
{
DataTable workSheet = GetExcelDataAsDataSet(path, isFirstRowAsColumnNames).Tables[workSheetName];
if (workSheet == null)
throw new WorksheetDoesNotExistException(string.Format("The worksheet {0} does not exist, has an incorrect name, or does not have any data in the worksheet", workSheetName));
return workSheet;
}
private static IEnumerable<DataRow> GetData(string path, string workSheetName, bool isFirstRowAsColumnNames = true)
{
return from DataRow row in GetExcelWorkSheet(path, workSheetName, isFirstRowAsColumnNames).Rows select row;
}
I think you'll find that Excel's COM interface is very similar to VBA in that the class libraries are all identical. The only challenge is in grabbing the Excel instance and then managing the syntactical differences (ie VBA uses parentheses for indexers, and C# uses square brackets).
Assuming your VBA works, this should be the identical code in C# to grab an open instance of Excel and do what you have done. If you want to open a new instance of Excel, that's actually even easier (and very easy to Google):
Excel.Application excel;
Excel.Workbook wb;
try
{
excel = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
excel.Visible = true;
wb = (Excel.Workbook)excel.ActiveWorkbook;
}
catch (Exception ex)
{
ErrorMessage = "Trouble Locating Open Excel Instance";
return;
}
Excel.Worksheet sheet = wb.Worksheets["Sheet1"];
foreach (Excel.ListObject lo in sheet.ListObjects)
{
Excel.Range srcRow = lo.DataBodyRange;
Excel.ListRow oLastRow = wb.Worksheets["Sheet2"].ListObjects["table1"].ListRows.Add();
srcRow.Copy();
oLastRow.Range.PasteSpecial(Excel.XlPasteType.xlPasteValues);
}
This all presupposes you have referenced Excel COM and set your using:
using Excel = Microsoft.Office.Interop.Excel;
Related
I am using the below code to trim all cells in my DataTable.
The problem is, that I am doing it through a loop, and depending on what I fill the DataTable with, if it has 1500 rows and 20 columns, the loop takes a really, really long time.
DataColumn[] stringColumns = dtDataTable.Columns.Cast<DataColumn>().Where(c => c.DataType == typeof(string)).ToArray();
foreach (DataRow row in dtDataTable.Rows)
{
foreach (DataColumn col in stringColumns)
{
if (row[col] != DBNull.Value)
{
row.SetField<string>(col, row.Field<string>(col).Trim());
}
}
}
And here is how I am importing my Excel sheet to the DataTable:
using (OpenFileDialog ofd = new OpenFileDialog() { Title = "Select File", Filter = "Excel WorkBook|*.xlsx|Excel WorkBook 97-2003|*.xls|All Files(*.*)|*.*", Multiselect = false, ValidateNames = true })
{
if (ofd.ShowDialog() == DialogResult.OK)
{
String PathName = ofd.FileName;
FileName = System.IO.Path.GetFileNameWithoutExtension(ofd.FileName);
strConn = string.Empty;
FileInfo file = new FileInfo(PathName);
if (!file.Exists) { throw new Exception("Error, file doesn't exists!"); }
string extension = file.Extension;
switch (extension)
{
case ".xls":
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + PathName + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'";
case ".xlsx":
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + PathName + ";Extended Properties='Excel 12.0;HDR=Yes;IMEX=1;'";
default:
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + PathName + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'";
}
}
else
{
return;
}
}
using (OleDbConnection cnnxls = new OleDbConnection(strConn))
{
using (OleDbDataAdapter oda = new OleDbDataAdapter(string.Format("select * from [{0}$]", "Sheet1"), cnnxls))
{
oda.Fill(dtDataTableInitial);
}
}
//Clone dtDataTableInitial so that I can have the new DataTable in String Type
dtDataTable = dtDataImportInitial.Clone();
foreach (DataColumn col in dtDataTable.Columns)
{
col.DataType = typeof(string);
}
foreach (DataRow row in dtDataImportInitial.Rows)
{
dtDataTable.ImportRow(row);
}
Is there a more efficient way of accomplishing this?
EDIT: As per JQSOFT's suggestion, I am using OleDbDataReader now, but am still running two issues:
One: SELECT RTRIM(LTRIM(*)) FROM [Sheet1$] doesn't seem to work.
I know that it is possible to select each column one by one, but the number of and header of the columns in the excel sheet is random, and I am not sure how to adjust my SELECT string to account for this.
Two: A column whose rows are mostly populated with numbers, but have a few rows with letters seem to have those rows with letters omitted. For example:
Col1
1
2
3
4
5
6
a
b
Becomes:
Col1
1
2
3
4
5
6
However, I have discovered that if I manually go into the excel sheet and convert the entire table cell format to "Text", this issue is resolved. However, doing this converts any dates in that excel sheet into unrecognizable strings of numbers, so I want to avoid doing this if at all possible.
For example: 7/2/2020 becomes 44014 if converted to "Text".
Here is my new code:
private void Something()
{
if (ofd.ShowDialog() == DialogResult.OK)
{
PathName = ofd.FileName;
FileName = System.IO.Path.GetFileNameWithoutExtension(ofd.FileName);
strConn = string.Empty;
FileInfo file = new FileInfo(PathName);
if (!file.Exists) { throw new Exception("Error, file doesn't exists!"); }
}
using (OleDbConnection cn = new OleDbConnection { ConnectionString = ConnectionString(PathName, "No") })
{
using (OleDbCommand cmd = new OleDbCommand { CommandText = query, Connection = cn })
{
cn.Open();
OleDbDataReader dr = cmd.ExecuteReader();
dtDataTable.Load(dr);
}
}
dataGridView1.DataSource = dtDataTable;
}
public string ConnectionString(string FileName, string Header)
{
OleDbConnectionStringBuilder Builder = new OleDbConnectionStringBuilder();
if (Path.GetExtension(FileName).ToUpper() == ".XLS")
{
Builder.Provider = "Microsoft.Jet.OLEDB.4.0";
Builder.Add("Extended Properties", string.Format("Excel 8.0;IMEX=1;HDR=Yes;", Header));
}
else
{
Builder.Provider = "Microsoft.ACE.OLEDB.12.0";
Builder.Add("Extended Properties", string.Format("Excel 12.0;IMEX=1;HDR=Yes;", Header));
}
Builder.DataSource = FileName;
return Builder.ConnectionString;
}
OleDb Objects
Actually what I meant is, to get formatted/trimmed string values from the Excel Sheet and create a DataTable with DataColumn objects of string type only, use the forward-only OleDbDataReader to create both, DataColumn and DataRow objects as it reads. Doing so, the data will be modified and filled in one step hence no need to call another routine to loop again and waste some more time. Also, consider using asynchronous calls to speed up the process and avoid freezing the UI while executing the lengthy task.
Something might help you to go:
private async void TheCaller()
{
using (var ofd = new OpenFileDialog
{
Title = "Select File",
Filter = "Excel WorkBook|*.xlsx|Excel WorkBook 97 - 2003|*.xls|All Files(*.*)|*.*",
AutoUpgradeEnabled = true,
})
{
if (ofd.ShowDialog() != DialogResult.OK) return;
var conString = string.Empty;
var msg = "Loading... Please wait.";
try
{
switch (ofd.FilterIndex)
{
case 1: //xlsx
conString = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={ofd.FileName};Extended Properties='Excel 12.0;HDR=Yes;IMEX=1;'";
break;
case 2: //xls
conString = $"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={ofd.FileName};Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'";
break;
default:
throw new FileFormatException();
}
var sheetName = "sheet1";
var dt = new DataTable();
//Optional: a label to show the current status
//or maybe show a ProgressBar with ProgressBarStyle = Marquee
lblStatus.Text = msg;
await Task.Run(() =>
{
using (var con = new OleDbConnection(conString))
using (var cmd = new OleDbCommand($"SELECT * From [{sheetName}$]", con))
{
con.Open();
using (var r = cmd.ExecuteReader())
while (r.Read())
{
if (dt.Columns.Count == 0)
for (var i = 0; i < r.FieldCount; i++)
dt.Columns.Add(r.GetName(i).Trim(), typeof(string));
object[] values = new object[r.FieldCount];
r.GetValues(values);
dt.Rows.Add(values.Select(x => x?.ToString().Trim()).ToArray());
}
}
});
//If you want...
dataGridView1.DataSource = null;
dataGridView1.DataSource = dt;
msg = "Loading Completed";
}
catch (FileFormatException)
{
msg = "Unknown Excel file!";
}
catch (Exception ex)
{
msg = ex.Message;
}
finally
{
lblStatus.Text = msg;
}
}
}
Here's a demo, reading sheets with 8 columns and 5000 rows from both xls and xlsx files:
Less than a second. Not bad.
However, this will not work correctly if the Sheet has mixed-types columns like your case where the third column has string and int values in different rows. That because the data type of a column is guessed in Excel by examining the first 8 rows by default. Changing this behavior requires changing the registry value of TypeGuessRows in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\x.0\Engines\Excel from 8 to 0 to force checking all the rows instead of just the first 8. This action will dramatically slow down the performance.
Office Interop Objects
Alternatively, you could use the Microsoft.Office.Interop.Excel objects to read the Excel Sheet, get and format the values of the cells regardless of their types.
using Excel = Microsoft.Office.Interop.Excel;
//...
private async void TheCaller()
{
using (var ofd = new OpenFileDialog
{
Title = "Select File",
Filter = "Excel WorkBook|*.xlsx|Excel WorkBook 97 - 2003|*.xls|All Files(*.*)|*.*",
AutoUpgradeEnabled = true,
})
{
if (ofd.ShowDialog() != DialogResult.OK) return;
var msg = "Loading... Please wait.";
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook = null;
try
{
var dt = new DataTable();
lblStatus.Text = msg;
await Task.Run(() =>
{
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(ofd.FileName, Type.Missing, true);
var xlSheet = xlWorkBook.Sheets[1] as Excel.Worksheet;
var xlRange = xlSheet.UsedRange;
dt.Columns.AddRange((xlRange.Rows[xlRange.Row] as Excel.Range)
.Cells.Cast<Excel.Range>()
.Where(h => h.Value2 != null)
.Select(h => new DataColumn(h.Value2.ToString()
.Trim(), typeof(string))).ToArray());
foreach (var r in xlRange.Rows.Cast<Excel.Range>().Skip(1))
dt.Rows.Add(r.Cells.Cast<Excel.Range>()
.Take(dt.Columns.Count)
.Select(v => v.Value2 is null
? string.Empty
: v.Value2.ToString().Trim()).ToArray());
});
(dataGridView1.DataSource as DataTable)?.Dispose();
dataGridView1.DataSource = null;
dataGridView1.DataSource = dt;
msg = "Loading Completed";
}
catch (FileFormatException)
{
msg = "Unknown Excel file!";
}
catch (Exception ex)
{
msg = ex.Message;
}
finally
{
xlWorkBook?.Close(false);
xlApp?.Quit();
Marshal.FinalReleaseComObject(xlWorkBook);
Marshal.FinalReleaseComObject(xlApp);
xlWorkBook = null;
xlApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();
lblStatus.Text = msg;
}
}
}
Note: You need to add reference to the mentioned library.
Not fast especially with a big number of cells but it gets the desired output.
I use this function to read excel file to datatable:
public static DataTable exceldata(string filePath)
{
try
{
DataTable dtexcel = new DataTable();
bool hasHeaders = false;
string HDR = hasHeaders ? "Yes" : "No";
string strConn;
if (filePath.Substring(filePath.LastIndexOf('.')).ToLower() == ".xlsx")
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=\"Excel 12.0;IMEX=1;HDR=YES;TypeGuessRows=0;ImportMixedTypes=Text\"";
else
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=\"Excel 8.0;IMEX=1;HDR=YES;TypeGuessRows=0;ImportMixedTypes=Text\"";
OleDbConnection conn = new OleDbConnection(strConn);
conn.Open();
DataTable schemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
DataRow schemaRow = schemaTable.Rows[0];
string sheet = schemaRow["TABLE_NAME"].ToString();
if (!sheet.EndsWith("_"))
{
string query = "SELECT * FROM [" + sheet + "]";
OleDbDataAdapter daexcel = new OleDbDataAdapter(query, conn);
dtexcel.Locale = CultureInfo.CurrentCulture;
daexcel.Fill(dtexcel);
}
conn.Close();
return dtexcel;
}
catch (Exception ex)
{
return null;
}
}
My trouble is: When Excel file have some cells that format look like number (ex: 301/1, 181/3 .... ), the datatable return empty value in that cells.
How can read Excel files to datatable that cells as string, not number detected ?
I know you've specifically asked to use an excel sheet. As someone who has faced the exact same issue, I would recommend you to use ClosedXML instead of using an Oledb connection.
Closed XML is much faster to read and allows you to get contents of an entire sheet or a cell very easily.
I've answered another question similar to this one here
https://stackoverflow.com/a/47235686/6729097
If anyone can help me out it will be very grateful. I am trying to read an excel (.xlsx, excel-2007) which have different sheets (Headers are not fixed). The below code works for me in most of the cases, but throws exception in some of the cases as entitled.
public static bool ReadExcelData(string ExcelFilePath, string SheetName, out DataTable dt)
{
dt = new DataTable();
bool isXlsx = ExcelFilePath.Substring(ExcelFilePath.LastIndexOf('.') + 1).ToLower() == "xlsx";
string excelConnectString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + ExcelFilePath + ";Extended Properties=\"Excel 8.0;HDR=yes;\"";
if (isXlsx)
excelConnectString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ExcelFilePath + ";Extended Properties=\"Excel 12.0\";";
OleDbConnection objConn = null;
try
{
objConn = new OleDbConnection(excelConnectString);
if (objConn.State == ConnectionState.Closed)
{
objConn.Open();
dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
}
}
catch (Exception ex)
{
dt = null;
return false;
}
try
{
dt.Clear();
string query = "select * from ["+SheetName+"$] ";
OleDbCommand objCmd = new OleDbCommand(query, objConn);
OleDbDataAdapter objDatAdap = new OleDbDataAdapter();
objDatAdap.SelectCommand = objCmd;
objDatAdap.Fill(dt);
Boolean result = (dt.Rows.Count >= 1) ? true : false;
objConn.Close();
return true;
}
catch (Exception ex)
{
dt = null;
return false;
}
}
If, in case of exception, I open this excel (on which it is giving error) manually (double clicking the excel) before going in to the code, it will not generate any exception, rather reads that excel smoothly.
What can be better or alternative way so that it may work for all the cases?
Issue is in your excel sheet, not in your code, please just saveas your excel sheet in .xls or .xlsx format again and then use the same code. It will work.
I want to get excel sheet used data range by using oledb.
Code is below,
String strExcelConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=E:\\DOTNET\\CrsMicro\\CA.xls;"
+ "Extended Properties='Excel 8.0;HDR=Yes'";
using (OleDbConnection connExcel = new OleDbConnection(strExcelConn))
{
string selectString = "SELECT * FROM [CA$A1:D500]";
using (OleDbCommand cmdExcel = new OleDbCommand(selectString,connExcel))
{
cmdExcel.Connection = connExcel;
connExcel.Open();
DataTable dt=new DataTable();
OleDbDataAdapter adp = new OleDbDataAdapter();
adp.SelectCommand = cmdExcel;
adp.FillSchema(dt, SchemaType.Source);
adp.Fill(dt);
int range=dt.Columns.Count;
int row = dt.Rows.Count;
//var result = cmdExcel.ExecuteReader();
//DataTable dtExcelSchema;
//dtExcelSchema = connExcel.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
// string excelsheetname = dtExcelSchema.Rows[0].ItemArray[2].ToString();
connExcel.Close();
//string sheetName = dtExcelSchema.Rows[0]["TABLE_NAME"].ToString();
}
}
my sheet range is not always A1:D500, it may vary frequently. So i need to get the sheet range dynamically. I know this can be achieved by interop, but i need to do it in oledb. Any suggestion?
create a named range:
https://msdn.microsoft.com/EN-US/library/office/ff196817.aspx
and replace selectString to
"SELECT * FROM [CA$MyNamedRange]"
Hi I'm also working on same kind of problem in OLEDB C# excel, I found below solution. It works for me. But I'm new to C#, I'm not sure how efficient it is.
But it is satisfying my requirements so far. This may be helpful for others.
I was able to get dynamic range in an excel sheet from a browsed input excel file (make sure excel file doesn't contain hidden sheets). This works perfectly for excel workbook containing single sheet. I haven't tested with multiple sheets.
Range: A [stat value]: Column Name[0] // Returns all rows from start value till the column name.
Example: A1:M0 // It will return all rows from A1 till column M. So here no need to worry how many rows you have in your excel.
Just by giving Column Name[0] takes all rows from the starting till the column M.
So '0' will be our outer range.
//Code under actual c# clas file where we are uploading excel.
Excel_Common excelComm = new Excel_Common(); // object to Excel_Common class file
string rangeStringwithSHeet =excelComm.GetSheetName(filepath).ToString().Trim('\'') + GetRange(excelComm.GetSheetName(filepath), excelComm.ExcelConn(filepath));
queryForExcelInput = string.Format("SELECT * FROM [{0}]", rangeStringwithSHeet);
Econ1 = new OleDbConnection(excelComm.ExcelConn(filepath));
Econ1.Open();
dataExcelInputTable = new DataTable();
OleDbCommand oleDbCommand1 = new OleDbCommand(queryForExcelInput, Econ1);
OleDbDataAdapter oleDbDaAdapter1 = new OleDbDataAdapter(oleDbCommand1);
oleDbDaAdapter1.Fill(dataExcelInputTable);
Excel_Common class file has below methods:
//Get Range like A4:M30
public string GetRange(string SheetName, string excelConnectionString)
{
string rangeInput = "",rangeColName="";
int columnsCount = 0;
int rowStartRange = 0;
columnsCount = GetNumberOfColumnsInSheet(SheetName, excelConnectionString);
rowStartRange = GetStartRowRange(SheetName, excelConnectionString); // This is optional if you want always A1. just assign 1 here
while (columnsCount > 0)
{
columnsCount--;
rangeColName = (char)('A' + columnsCount % 26) + rangeColName;
columnsCount /= 26;
}
rangeInput = "A" + rowStartRange + ":" + rangeColName + "0";
return rangeInput;
}
// Get Sheet Name assuming only one sheet for workbook and no hidden sheets
public string GetSheetName(string filepath)
{
string sheetname = "";
String connect = ExcelConn(filepath);
OleDbConnection con = new OleDbConnection(connect);
con.Open();
DataTable tables = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
foreach (DataRow row in tables.Rows)
{
sheetname = row[2].ToString();
if (!sheetname.EndsWith("$"))
continue;
}
con.Close();
return sheetname;
}
// Get number of columns in a given sheet
public int GetNumberOfColumnsInSheet(string SheetName, string excelConnectionString)
{
int columnsCount = 0;
//If a valid excel file
if (!string.IsNullOrEmpty(excelConnectionString))
{
using (OleDbConnection conn = new OleDbConnection(excelConnectionString))
{
conn.Open();
DataTable dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, null);
if (dt.Rows.Count > 0)
columnsCount = dt.AsEnumerable().Where(a => a["TABLE_NAME"].ToString() == SheetName).Count();
conn.Close();
}
}
return columnsCount;
}
// Get the first row count in sheet contains some keyword . This method call is optional if you always want A1. Here I need to check some keyword exist and from there only I have to start something like A4
public int GetStartRowRange(string SheetName, string excelConnectionString)
{
int rowStartRange = 1;
//If a valid excel file
if (!string.IsNullOrEmpty(excelConnectionString))
{
using (OleDbConnection conn = new OleDbConnection(excelConnectionString))
{
string colValue;
conn.Open();
string cmdstr = "select * from [" + SheetName + "]";
OleDbCommand com = new OleDbCommand(cmdstr, conn);
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter(com);
da.Fill(dt);
// get first row data where it started
foreach (DataRow dataRow in dt.Rows)
{
colValue = dataRow[0].ToString();
if ((colValue.Contains("Value1") || colValue.Contains("Value2") || colValue.Contains("Value3")) && (string.IsNullOrEmpty(dataRow[1].ToString()) == false))
{
rowStartRange = rowStartRange + 1;
break;
}
else
{
rowStartRange = rowStartRange + 1;
}
}
conn.Close();
}
}
return rowStartRange;
}
// Connection to excel document
public string ExcelConn(string FilePath)
{
string constr = "";
string extension = Path.GetExtension(FilePath);
//Checking for the extentions, if XLS connect using Jet OleDB
if (extension.Equals(".xls", StringComparison.CurrentCultureIgnoreCase))
{
constr = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0};Extended Properties=\"Excel 12.0;IMEX=1;HDR=YES\"", FilePath);
}
//Use ACE OleDb if xlsx extention
else if (extension.Equals(".xlsx", StringComparison.CurrentCultureIgnoreCase))
{
constr = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 8.0;IMEX=1;HDR=YES\"", FilePath);
}
return constr;
} // end of ExcelConn method
I am trying to read an excel file in excel, but for some reason sometime, the first column is missing and first row is missing from the data.
When I open the file in excel and save it without any changes, the files are read correctly.
Any ideas about how this might happen?
Below is the code i am using to read the file:
string xlConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source="
+ txt_InputFile.Text
+ ";Extended Properties=Excel 8.0;";
using (OleDbConnection dbConnection = new OleDbConnection(xlConn))
{
dbConnection.Open();
// Get the name of the first worksheet:
DataTable dbSchema = dbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dbSchema == null || dbSchema.Rows.Count < 1)
{
//"Error: Could not determine the name of the first worksheet."
throw new Exception(Program.lm_GetMethodLanguage(this.GetType().Name, "wp_InputFile_CloseFromNext", 5) );
}
string firstSheetName = dbSchema.Rows[0]["TABLE_NAME"].ToString();
using (
OleDbDataAdapter dbCommand = new OleDbDataAdapter("SELECT * FROM [" + firstSheetName + "]",
dbConnection))
{
using (DataSet myDataSet = new DataSet())
{
dbCommand.Fill(myDataSet);
inputData = myDataSet.Tables[0];
}
}
}
Use this.This will retrieve all the sheets in excel sheet.
private String[] GetExcelSheetNames(string excelFile)
{
try
{
excelConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ""yoursourcepath"+ ";Extended Properties=Excel 12.0;Persist Security Info=False";
excelConnection = new OleDbConnection(excelConnectionString);
excelConnection.Open();
dt = excelConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return null;
}
excelSheets = new String[dt.Rows.Count];
int i = 0;
foreach (DataRow row in dt.Rows)
{
excelSheets[i] = row["TABLE_NAME"].ToString();
i++;
}
return excelSheets;
}
catch (Exception ex)
{
return null;
}
finally
{
if (excelConnection != null)
{
excelConnection.Close();
excelConnection.Dispose();
}
if (dt != null)
{
dt.Dispose();
}
}
}