只能在Ms Excel中打开时才能读取Excel文件

我正在使用下面的代码来打开一个Excel文件(XLS)并填充第一个工作表DataTable

 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]; 

只有在Excel文件已经打开的情况下才有效。 为什么会这样?

如果文件没有打开,我得到一个错误消息(在线connExcel.Open ): External table is not in the expected format.

我面临着同样的问题,因此对于这个网站,许多开发者都在为同样的问题而苦苦挣扎:

– 当我尝试使用OLE DB读取Excel时,所有值都是空的

– 除非文件已经打开,否则不能连接到excel文件

其实我正在使用经典的连接string(请注意,我试图读取97/2003文件):

 Provider=Microsoft.Jet.OLEDB.4.0; Data Source = " + GetFilename(filename) + "; Extended Properties ='Excel 8.0;HDR=NO;IMEX=1' 

但只有在以下情况下才能正确读取文件:

  • 在Excel中甚至在Word中打开! (该文件当然看起来是损坏的和不可读的,但是然后OleDb过程可以读取文件的每一行),我没有尝试与其他Office应用程序

  • 该文件不处于只读模式

我也尝试手动locking文件或与其他非办公应用程序打开它,但结果是不一样的。 如果我遵循以前的两个规则(在Word或Excel中以非只读模式打开文件),我可以看到所有单元格,否则似乎第一被完全忽略(所以F2变成了F1,F3变成了F2,…而F6,最后一个,应该变成F5,否则会抛出索引错误)。

为了保持与OleDb的兼容性而不使用第三方库,我使用Microsoft.Office.Interop.Excel程序集发现了一个非常愚蠢的解决方法。

 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); } } 

本质上,前3行运行的是一个Excel实例,它持续完成OleDb执行任务所需的时间。 finally块内的最后4行让Excel实例在任务之后立即closures,并避免虚幻Excel进程。

我重申这是一个非常愚蠢的解决方法,还需要一个1,5 MB的dll(Microsoft.Office.Interop.Excel.dll)被添加到项目。 无论如何,似乎不可能OleDb不能自己pipe理丢失的数据…

我有同样的问题。 如果文件是打开的,读取是好的,但如果文件closures了…有些事情是奇怪的…在我的情况下,我收到来自列和值奇怪的数据..debugging我发现第一个工作表的名称,很奇怪[“xls _xlnm#_FilterDatabase”]在互联网上我发现这是一个隐藏的名单和一个技巧,以避免阅读这张表( 这里 ),所以我已经实现了一个方法:

 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; } 

对我来说工作得很好。

我完整的示例代码是:

 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; } 

ToString()是否失败,像这样? 错误是“对象引用未设置为对象的实例”

Convert.ToString()修复了什么?