我有一个Excel工作表我想读入数据表 - 除了Excel表格中的一个特定列之外,一切都很好.列,"产品ID",就像是值的组合##########
和n#########
.
我试图让OleDB通过将其读入数据集/数据表来自动处理所有内容,但"ProductID"中的任何值都会n######
丢失,忽略并留空.我尝试通过使用datareader循环遍历每一行来手动创建我的DataTable,但结果完全相同.
这是代码:
// add the column names manually to the datatable as column_1, column_2, ...
for (colnum = 0; colnum < num_columns; colnum ++){
ds.Tables["products"].Columns.Add("column_" +colnum , System.Type.GetType("System.String"));
}
while(myDataReader.Read()){
// loop through each excel row adding a new respective datarow to my datatable
DataRow a_row = ds.Tables["products"].NewRow();
for (col = 0; col < num_columns; col ++){
try { a_row[col] = rdr.GetString(col); }
catch { a_row[col] = rdr.GetValue(col).ToString(); }
}
ds.Tables["products"].Rows.Add(a_row);
}
我不明白为什么它不会让我读到像这样的价值观n######
.我怎样才能做到这一点?
使用.Net 4.0和读取Excel文件,我遇到了类似的问题OleDbDataAdapter
- 即在MS Excel中的"PartID"列上读取混合数据类型,其中PartID值可以是数字(例如561)或文本(例如HL4354) ,即使excel列被格式化为"Text".
据我所知,ADO.NET根据列中的大多数值选择数据类型(与数值数据类型相关联).即,如果样本集中的大多数PartID都是数字,则ADO.NET会将该列声明为数字.因此,ADO.Net将尝试将每个单元格转换为数字,这对于"text"PartID值将失败,而不会导入那些"text"PartID.
我的解决方案是设置OleDbConnection
连接字符串以用于Extended Properties=IMEX=1;HDR=NO
指示这是一个导入,并且表格不包含标题.excel文件有一个标题行,所以在这种情况下告诉ado.net不要使用它.然后在代码中,从数据集中删除该标题行,并且该列具有混合数据类型.
string sql = "SELECT F1, F2, F3, F4, F5 FROM [sheet1$] WHERE F1 IS NOT NULL";
OleDbConnection connection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + PrmPathExcelFile + @";Extended Properties=""Excel 8.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text""");
OleDbCommand cmd = new OleDbCommand(sql, connection);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
ds.Tables.Add("xlsImport", "Excel");
da.Fill(ds, "xlsImport");
// Remove the first row (header row)
DataRow rowDel = ds.Tables["xlsImport"].Rows[0];
ds.Tables["xlsImport"].Rows.Remove(rowDel);
ds.Tables["xlsImport"].Columns[0].ColumnName = "LocationID";
ds.Tables["xlsImport"].Columns[1].ColumnName = "PartID";
ds.Tables["xlsImport"].Columns[2].ColumnName = "Qty";
ds.Tables["xlsImport"].Columns[3].ColumnName = "UserNotes";
ds.Tables["xlsImport"].Columns[4].ColumnName = "UserID";
connection.Close();
//现在您可以使用LINQ搜索字段
var data = ds.Tables["xlsImport"].AsEnumerable();
var query = data.Where(x => x.Field("LocationID") == "COOKCOUNTY").Select(x =>
new Contact
{
LocationID= x.Field("LocationID"),
PartID = x.Field("PartID"),
Quantity = x.Field("Qty"),
Notes = x.Field("UserNotes"),
UserID = x.Field("UserID")
});
我发现的几个论坛声称通过IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text
在连接字符串中添加扩展属性可以解决问题,但事实并非如此.我终于通过在连接字符串中的扩展属性中添加"HDR = NO"解决了这个问题(正如上面的Brian Wells所示),这样我就可以导入混合类型了.
然后我添加了一些通用代码来命名第一行数据后面的列,然后删除第一行.
public static DataTable ImportMyDataTableFromExcel(string filePath) { DataTable dt = new DataTable(); string fullPath = Path.GetFullPath(filePath); string connString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=\"" + fullPath + "\";" + "Extended Properties=\"Excel 8.0;HDR=No;IMEX=1;\""; string sql = @"SELECT * FROM [sheet1$]"; using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter(sql, connString)) { dataAdapter.Fill(dt); } dt = BuildHeadersFromFirstRowThenRemoveFirstRow(dt); return dt; } private static DataTable BuildHeadersFromFirstRowThenRemoveFirstRow(DataTable dt) { DataRow firstRow = dt.Rows[0]; for (int i = 0; i < dt.Columns.Count; i++) { if(!string.IsNullOrWhiteSpace(firstRow[i].ToString())) // handle empty cell dt.Columns[i].ColumnName = firstRow[i].ToString().Trim(); } dt.Rows.RemoveAt(0); return dt; }
有两种方法可以处理混合数据类型和excel.
方法1
打开Excel电子表格并手动将列格式设置为所需的格式.在这种情况下,'文字'.
方法2
有一个"黑客",包括将"IMEX = 1"附加到您的连接字符串,如下所示:
Provider = Microsoft.Jet.OLEDB.4.0; Data Source = myfile.xls; Extended Properties = Excel 8.0; IMEX = 1
这将尝试根据在注册表中设置的方式处理混合Excel格式.这可以由您在本地设置,但对于服务器,这可能不是一个选项.
没问题sh4,很高兴它有助于混合型问题.
DateTime列是我记得的其他动物过去让我感到悲伤...我们有一个excel文件我们处理OleDbDataAdapter有时会将日期转换为双数据类型(显然Excel将日期存储为双精度数,编码数字自1900年1月0日起经过的几天).
解决方法是使用:
OleDbConnection mobjExcelConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + txtExcelFile.Text + @";Extended Properties=""Excel 8.0;IMEX=1;HDR=Yes;"""); OleDbDataAdapter mobjExcelDataAdapter = new OleDbDataAdapter("Select * from [" + txtSheet.Text + "$] where [Supplier ID] <> '' ", mobjExcelConn); DateTime dtShipStatus = DateTime.MinValue; shipStatusOrig = excelRow["Est Ship Date"].ToString(); // excelRow is DataRow in the DataSet via the OleDbDataAdapter if (shipStatusOrig != string.Empty) { // Date may be read in via oledb adapter as a double if (IsNumeric(shipStatusOrig)) { double d = Convert.ToDouble(shipStatusOrig); dtShipStatus = DateTime.FromOADate(d); if (DateTime.TryParse(dtShipStatus.ToString(), out dtShipStatus)) { validDate = true; Debug.WriteLine("{0} converted: ", dtShipStatus.ToString("s")); } } else { if (ValidateShipDate(shipStatusOrig)) { dtShipStatus = DateTime.Parse(shipStatusOrig); validDate = true; Debug.WriteLine("{0} converted: ", dtShipStatus.ToString("s")); } else { validDate = false; MessageBox.Show("Invalid date format in the Excel spreadsheet.\nLine # " + progressBar1.Value + ", the 'Ship Status' value '" + shipStatusOrig + "' is invalid.\nDate should be in a valid date time format.\ne.g. M/DD/YY, M.D.Y, YYYY-MM-DD, etc.", "Invaid Ship Status Date"); } } ... } public static Boolean IsNumeric (Object Expression) { if(Expression == null || Expression is DateTime) return false; if(Expression is Int16 || Expression is Int32 || Expression is Int64 || Expression is Decimal || Expression is Single || Expression is Double || Expression is Boolean) return true; try { if(Expression is string) Double.Parse(Expression as string); else Double.Parse(Expression.ToString()); return true; } catch {} // just dismiss errors but return false return false; } public bool ValidateShipDate(string shipStatus) { DateTime startDate; try { startDate = DateTime.Parse(shipStatus); return true; } catch { return false; } }