Import from Excel in C# - c#

I use following code to save data from excel file into table
private void RetrieveAndStoreExcelData(String filePath)
{
String excelConnectionStr = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source='" + filePath + "'; Extended Properties='Excel 8.0;'";
OleDbConnection excelConnection = new OleDbConnection(excelConnectionStr);
excelConnection.Open();
try
{
//Get the name of the first worksheet
DataTable schema = excelConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (schema == null || schema.Rows.Count < 1)
{
throw new Exception("Error: Could not determine the name of the first worksheet.");
}
string firstSheetName = schema.Rows[0]["TABLE_NAME"].ToString();
//Retrieve data from worksheet into reader
string query = "SELECT * FROM [" + firstSheetName + "]";
OleDbCommand command = new OleDbCommand(query, excelConnection);
OleDbDataReader dbReader = command.ExecuteReader(); //IEnumerable
//populate IEnumerable
if (dbReader.HasRows)
{
populateRecords(dbReader);
}
}
finally
{
excelConnection.Close();
}
}
This works fine. But if one of the fields length is greater than 255 characters then it truncates the string to 255 and that is also when that row appears after 10th row in excel sheet.
So, if first 10 rows is having length less than 255, it assumes that all rows will have length less than 255 characters.
So is there any way to solve this?

Related

C# reading Excel missing column

I have excel (.xls) file with 4 column and all columns are "general" and with no header.
Column A and B contains some text, column C contains numbers, column D contains text.
When I read data (code below) reader can see only 3 columns (A,B,C), reader dose not see (recognize) column D (picture below).
I have added IMEX=1 in connection string, I have changed registry - TypeGuessRows set it to 0 (image below), but all of this did not help me - still have same problem.
Does anyone know why after column that contains numbers JET dose not see txt column?
string sourceFileServer = #"C:\TEST\Excel1.xls";
using (OleDbConnection connection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + sourceFileServer + ";Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1\";"))
{
OleDbCommand command = new OleDbCommand("SELECT * FROM [Sheet1$];", connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
int _row = 0;
while (reader.Read())
{
_row++;
try
{
string _v0 = ((string)reader[0]).Trim();
string _v1 = ((string)reader[1]).Trim();
string _v2 = reader[2].ToString().Trim();
string _v3 = ((string)reader[3]).Trim();
MessageBox.Show(_v0 + "|" + _v1 + "|" + _v2 + "|" + _v3 + "|");
}
catch (Exception xcp)
{
MessageBox.Show(xcp.Message);
}
break;
}
reader.Close();
}
reader
registry

Can only read Excel file when it is actually open in Ms Excel

I am using the following code to open an excel file (XLS) and populate a DataTable with the first worksheet:
var connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;", filename);
OleDbConnection connExcel = new OleDbConnection(connectionString);
connExcel.Open();
DataTable dtExcelSchema;
dtExcelSchema = connExcel.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string SheetName = dtExcelSchema.Rows[0]["TABLE_NAME"].ToString();
connExcel.Close();
var adapter = new OleDbDataAdapter("SELECT * FROM [" + SheetName + "]", connectionString);
var ds = new DataSet();
int count = 0;
adapter.Fill(ds, SheetName);
DataTable dt = ds.Tables[0];
It works only when the file is already open in Ms Excel. Why could that be?
If the file is not open, I get an error message (on line connExcel.Open): External table is not in the expected format.
I'm facing the same problem and accordingly to this site, many developers are struggling for the same:
-When I try read Excel with OLE DB all values are empty
-Can't connect to excel file unless file is already open
Actually I'm using the classic connection string (note that I'm trying to read a 97/2003 file):
Provider=Microsoft.Jet.OLEDB.4.0; Data Source = " + GetFilename(filename) + "; Extended Properties ='Excel 8.0;HDR=NO;IMEX=1'
but the file can be read properly only if:
Is open in Excel or even in Word! (the file of course appears corrupted and unreadable, but then the OleDb procedure can read every line of the file), I didn't try with other Office apps
The file is not in read-only mode
I also tried to lock the file manually or to open it with other non-office applications, but the result is not the same. If I follow the two previous rules (file opened in Word or Excel in not read-only mode) I can see all the cells, otherwise it seems the first column is ignored completely (so F2 became F1, F3 became F2,... and F6, the last one, should became F5 otherwise it throws and out-of-index error).
In order to keep compatibility with OleDb without using 3rd parties libraries I found a very stupid workaround using Microsoft.Office.Interop.Excel assembly.
Excel.Application _app = new Excel.Application();
var workbooks = _app.Workbooks;
workbooks.Open(_filename);
// OleDb Connection
using (OleDbConnection conn = new OleDbConnection(connectionOleDb))
{
try
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = String.Format("SELECT * FROM [{0}$]", tableName);
OleDbDataReader myReader = cmd.ExecuteReader();
int i = 0;
while (myReader.Read())
{
//Here I read through all Excel rows
}
}
catch (Exception E)
{
MessageBox.Show("Error!\n" + E.Message);
}
finally
{
conn.Close();
workbooks.Close();
if (workbooks != null)
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
_app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(_app);
}
}
Essentially the first 3 lines run an Excel instance that lasts exactly the time needed to OleDb to perform its tasks.
The last 4 lines, inside the finally block, let the Excel instance to be closed correctly, immediately after the task and avoid ghost Excel processes.
I repeat it's a very stupid workaround that also requires a 1,5 MB dll (Microsoft.Office.Interop.Excel.dll) to be added to the project.
Anyway seems impossible that OleDb cannot manage by itself the missing data...
I had the same problem. If the file was open the read was ok but if the file was closed... some thing was strange... in my case I received strange data from columns and values.. Debugging I found the name of the first sheet and was strange ["xls _xlnm#_FilterDatabase"] looking on the internet I found that's a name of hidden sheet and a trick to avoid read this sheet (HERE) and so I've implemented a method:
private string getFirstVisibileSheet(DataTable dtSheet, int index = 0)
{
string sheetName = String.Empty;
if (dtSheet.Rows.Count >= (index + 1))
{
sheetName = dtSheet.Rows[index]["TABLE_NAME"].ToString();
if (sheetName.Contains("FilterDatabase"))
{
return getFirstVisibileSheet(dtSheet, ++index);
}
}
return sheetName;
}
To me worked very well.
My complete example code is:
string excelFilePath = String.Empty;
string stringConnection = String.Empty;
using (OpenFileDialog openExcelDialog = new OpenFileDialog())
{
openExcelDialog.Filter = "Excel 2007 (*.xlsx)|*.xlsx|Excel 2003 (*.xls)|*.xls";
openExcelDialog.FilterIndex = 1;
openExcelDialog.RestoreDirectory = true;
DialogResult windowsResult = openExcelDialog.ShowDialog();
if (windowsResult != System.Windows.Forms.DialogResult.OK)
{
return;
}
excelFilePath = openExcelDialog.FileName;
using (DataTable dt = new DataTable())
{
try
{
if (!excelFilePath.Equals(String.Empty))
{
stringConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excelFilePath + ";Extended Properties='Excel 8.0; HDR=YES;';";
using (OleDbConnection conn = new OleDbConnection(stringConnection))
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string sheetName = getFirstVisibileSheet(dtSheet);
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
cmd = null;
conn.Close();
}
}
//Read and Use my DT
foreach (DataRow row in dt.Rows)
{
//On my case I need data on first and second Columns
if ((row.ItemArray.Count() < 2) ||
(row[0] == null || String.IsNullOrWhiteSpace(row[0].ToString()))
||
(row[1] == null ||String.IsNullOrWhiteSpace(row[1].ToString())))
{
continue;
}
//Get the number from the first COL
int colOneNumber = 0;
Int32.TryParse(row[0].ToString(), out colOneNumber);
//Get the string from the second COL
string colTwoString = row[1].ToString();
//Get the string from third COL if is a file path valid
string colThree = (row.ItemArray.Count() >= 3
&& !row.IsNull(2)
&& !String.IsNullOrWhiteSpace(row[2].ToString())
&& File.Exists(row[2].ToString())
) ? row[2].ToString() : String.Empty;
}
}
catch (Exception ex)
{
MessageBox.Show("Import error.\n" + ex.Message, "::ERROR::", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private string getFirstVisibileSheet(DataTable dtSheet, int index = 0)
{
string sheetName = String.Empty;
if (dtSheet.Rows.Count >= (index + 1))
{
sheetName = dtSheet.Rows[index]["TABLE_NAME"].ToString();
if (sheetName.Contains("FilterDatabase"))
{
return getFirstVisibileSheet(dtSheet, ++index);
}
}
return sheetName;
}
Is it failing on ToString(), like here?
Error is "Object reference not set to an instance of an object"
Does Convert.ToString() fix anything?

Get Excel data range using oledb in c#

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

Search a row from a table which starts with asterisk symbol

I am uploading an excel file by using c# and i am selecting a column named LOT from that excel file.In column LOT one row is having number starting with asterisk symbol(*). I need a query to select all the rows. please Help me out in this.
I tried the below sample code but it is not working fine. Its returning the lots which doesn't have asterisk symbol(*).
protected void btnUpload_Click(object sender, EventArgs e)
{
//Get path from web.config file to upload
string FilePath = ConfigurationManager.AppSettings["FilePath"].ToString();
string filename = string.Empty;
//To check whether file is selected or not to uplaod
if (BrowseFile.HasFile)
{
try
{
string[] allowdFile = { ".xls", ".xlsx" };
//Here we are allowing only excel file so verifying selected file pdf or not
string FileExt = System.IO.Path.GetExtension(BrowseFile.PostedFile.FileName);
//Check whether selected file is valid extension or not
bool isValidFile = allowdFile.Contains(FileExt);
if (!isValidFile)
{
lblMsg.ForeColor = System.Drawing.Color.Red;
lblMsg.Text = "Please upload only Excel";
}
else
{
// Get size of uploaded file, here restricting size of file
int FileSize = BrowseFile.PostedFile.ContentLength;
if (FileSize <= 1048576)//1048576 byte = 1MB
{
//Get file name of selected file
filename = Path.GetFileName(Server.MapPath(BrowseFile.FileName));
//Save selected file into server location
BrowseFile.SaveAs(Server.MapPath(FilePath) + filename);
//Get file path
string filePath = Server.MapPath(FilePath) + filename;
//Open the connection with excel file based on excel version
OleDbConnection con = null;
if (FileExt == ".xls")
{
con = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=Excel 8.0;");
}
else if (FileExt == ".xlsx")
{
con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=Excel 12.0;");
}
con.Open();
//Get the list of sheet available in excel sheet
DataTable dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
//Get first sheet name
string getExcelSheetName = dt.Rows[0]["Table_Name"].ToString();
//Select rows from first sheet in excel sheet and fill into dataset
//OleDbCommand ExcelCommand = new OleDbCommand(#"SELECT LOT FROM [" + getExcelSheetName + #"] WHERE LOT IS NOT NULL", con);
OleDbCommand ExcelCommand = new OleDbCommand(#"SELECT LOT FROM [" + getExcelSheetName + #"] WHERE LOT LIKE '**'", con);
OleDbDataAdapter ExcelAdapter = new OleDbDataAdapter(ExcelCommand);
DataTable ExcelDataSet = new DataTable();
ExcelAdapter.Fill(ExcelDataSet);
//Holding the data into the list
List<DataRow> strLot = ExcelDataSet.AsEnumerable().ToList();
con.Close();
//string lots = "";
//seperating the each lot with a comma separator
for (int i = 0; i < strLot.Count; i++)
{
totLots += ExcelDataSet.Rows[i].ItemArray.GetValue(0).ToString() + ",";
}
//Removing the last comma separator
totLots = totLots.Remove(totLots.Length - 1);
You can use the LIKE operator
WHERE <Column> LIKE '\**'
Also, depending on your data source, the wildcard '*' could be replaced with '%' and 'LIKE' keyword could be replaced with 'ALIKE'
with '%' the search text will become '*%' instead of '\**'
Edit: Code below checked with .xls and .xlsx files
OleDbCommand ExcelCommand = new OleDbCommand(#"SELECT LOT FROM [" + getExcelSheetName + #"] WHERE LOT LIKE '*%'", con);
Change your command text to the following...
#"SELECT [LOT] FROM [" + getExcelSheetName + #"] WHERE [LOT] LIKE '\*%')"
This should preform a simple pattern match like a SQL script and look for any member of the column starting with an asterisk and containing anything at all after that.

Exporting Excel to Dataset ( ERROR - TOO MANY FIELDS DEFINED )

I am exporting a Excel (.xls) sheet to dataset. In that excel i am having 16 columns. While exporting i am getting the error " TOO MANY FIELDS DEFINED "..
Here is my code part..
{
string strFilePathOnServer = ConfigurationManager.AppSettings["RevenueDumpFileLocation"];
String sConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath(strFilePathOnServer) + RevenueDumpFileUpload.FileName + ";Extended Properties=\"Excel 8.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text\"";
string strPostedFileName = RevenueDumpFileUpload.PostedFile.FileName;
if (strPostedFileName != string.Empty && RevenueDumpFileUpload.PostedFile.ContentLength != 0)
{
RevenueDumpFileUpload.PostedFile.SaveAs(Server.MapPath(strFilePathOnServer) + RevenueDumpFileUpload.FileName);
RevenueDumpFileUpload.FileContent.Dispose();
}
OleDbConnection Exlcon = new OleDbConnection(sConnectionString);
try
{
//Exlcon.Open();
}
catch
{
return;
}
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM [Owner$]", Exlcon);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
objDataset1.Clear();
objAdapter1.Fill(objDataset1, "XLData");
When crossing the Fill method, i am getting the error...
How to sort out this...
Limit the column to only 250
string sql = "select * from [A1:IU]";

Categories

Resources