C#导入Excel:表头插HeaderTable失败+DataReader已打开错误求助
问题排查与修复方案
核心问题解析
- DataReader冲突错误:你在打开
headerreader(通过CommandBehavior.SchemaOnly)后,又调用adp.Fill(HeaderColumns),而Fill方法会再次执行同一个OleDbCommand,此时原DataReader未关闭,导致同一命令绑定了两个活跃的DataReader,触发"There is already an open DataReader..."错误。 - HeaderTable无数据:
CommandBehavior.SchemaOnly仅返回表的架构信息(列名、类型等),不包含任何行数据;同时你的连接字符串设置了HDR=YES,OLEDB会将Excel第一行识别为列名,无法直接查询到表头行内容。
修复步骤与代码调整
关键修正点
- 拆分命令与连接:为获取表头行和数据行分别处理,避免DataReader冲突
- 正确获取表头行:临时修改连接字符串的
HDR=NO,查询Excel第一行(即原表头行),再改回HDR=YES查询数据行 - 过滤无效工作表:跳过Excel内部的特殊表(名称含
xlnm)
修复后的代码
FileInfo[] files = directory.GetFiles("*.*", SearchOption.AllDirectories); foreach (FileInfo file in files) { string filename = file.Name; string excelFilePath = file.FullName; // 修正:使用单个文件的完整路径,而非文件夹路径 // 1. 处理表头行(Excel第一行) string headerConnStr = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={excelFilePath};Extended Properties=\"Excel 12.0 Xml;HDR=NO;\""; using (OleDbConnection headerCnn = new OleDbConnection(headerConnStr)) { headerCnn.Open(); DataTable sheetTable = headerCnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null); foreach (DataRow drSheet in sheetTable.Rows) { string sheetName = drSheet["TABLE_NAME"].ToString(); // 跳过Excel内部特殊表(如打印区域、隐藏表等) if (sheetName.Contains("xlnm")) continue; // 仅查询第一行(表头行),附加文件名和表名 string headerSql = $"select *,'{filename}' as filename,'{sheetName}' as sheetname from [{sheetName}$A1:IV1]"; using (OleDbCommand headerCmd = new OleDbCommand(headerSql, headerCnn)) using (OleDbDataReader headerReader = headerCmd.ExecuteReader()) using (SqlBulkCopy headBc = new SqlBulkCopy(myadoconn)) { headBc.DestinationTableName = "HeaderTable"; headBc.WriteToServer(headerReader); } } } // 2. 处理数据行(Excel第二行及以后) string dataConnStr = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={excelFilePath};Extended Properties=\"Excel 12.0 Xml;HDR=YES;\""; using (OleDbConnection dataCnn = new OleDbConnection(dataConnStr)) { dataCnn.Open(); DataTable sheetTable = dataCnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null); foreach (DataRow drSheet in sheetTable.Rows) { string sheetName = drSheet["TABLE_NAME"].ToString(); if (sheetName.Contains("xlnm")) continue; string dataSql = $"select *,'{filename}' as filename,'{sheetName}' as sheetname from [{sheetName}]"; using (OleDbCommand dataCmd = new OleDbCommand(dataSql, dataCnn)) using (OleDbDataReader dataReader = dataCmd.ExecuteReader()) using (SqlBulkCopy dataBc = new SqlBulkCopy(myadoconn)) { dataBc.DestinationTableName = "DataTable"; dataBc.WriteToServer(dataReader); } } } }
额外优化建议
- 参数化查询:避免直接拼接文件名和表名到SQL语句,防止潜在的注入风险(Excel场景风险较低,但建议养成规范习惯)
- 自动资源释放:所有实现
IDisposable的对象(连接、命令、读取器、批量拷贝)都用using包裹,无需手动调用Close(),确保资源自动回收 - 路径校验:可添加文件格式校验,仅处理
.xlsx/.xls等Excel格式文件,避免无效文件处理
内容的提问来源于stack exchange,提问作者Dinesh
相关产品推荐
相关产品推荐

