2

我有一个 asp.net C# 应用程序,我正在使用 OLEDBConnection 读取电子表格的内容。我正在使用下面的代码行从 excel 电子表格中读取数据。

 OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fullFilePath + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'");

我的一列有各种格式的数据,如字符串、数字、日期等,在不同的行中。运行时,当数据格式不同时,它不会从 excel 文件中读取该值。我在网上搜索了很多,发现我们需要在连接字符串中提及 IMEX 属性。我添加了,但没有正面回应!。

经过大量冲浪后,我发现任何内置的 Excel 驱动程序都会查询工作表的前 8 行,然后确定(未经您的许可或知识)它是什么类型的列,从而忽略任何不稍后在工作表中满足此数据类型。

http://www.mattjwilson.com/blog/2009/02/13/microsoft-excel-drivers-and-imex/

有没有办法摆脱这个问题?

4

4 回答 4

2

您遇到了 JET 引擎的众多有趣功能之一。这将基本上对每一行中的所有数据进行采样,并尝试猜测数据格式。如果您希望您的代码“正常工作”,那么有一个注册表设置将对此有所帮助。但是请注意,此注册表设置将影响 JET 如何处理系统上的所有导入,而不仅仅是您的特定导入。

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel]
"ImportMixedTypes"="Text"
"TypeGuessRows"=dword:00000000

此注册表设置将告诉 JET 在猜测格式之前检查列中每一行的格式。如果它发现混合内容,它将将该行作为文本导入。

默认情况下,JET 在类型猜测时测试前 25 行。

或者,您可以将 TypeGuessRows 更改为 1,JET 将仅在类型猜测时检查第一行。这意味着如果第一行是数字,第二行是字符串,JET 将假定所有行都是数字,您将无法使用 ADO.NET 读取它们

另一个警告:确保在编辑注册表时要小心。如果你不小心,你可以很快地摧毁你的系统。

于 2009-12-15T19:31:27.867 回答
1

更新:微软似乎真的不建议在服务器上使用 Excel COM 服务。尽管如此,许多开发人员在非 .NET(就像我的雇主所做的那样)和 .NET(请参阅此处)环境中都这样做,因为替代方案的成本很高。所有问题大部分都是可以解决的(除了大容量应用程序中潜在的可扩展性和性能问题以及在某些情况下的许可问题)。昂贵的替代方案是使用这样的第三方解决方案。

当一列中有不同数据类型的数据时,不应使用 OleDbConnection。您可以尝试使用 Excel COM/OLE API 从 Excel 读取,例如(从此处编译,可能包含错误):

在项目中包含以下参考:

Microsoft Excel 10.0 对象库

Microsoft Office 10.0 对象库

包括名称空间 Excel。

  using Excel;
  ...
      Excel.ApplicationClass xl = new Excel.Application();
      xl.Visible = false;
      xl.UserControl = false;
      Excel.Workbook theWorkbook = xl.Workbooks.Open(
         fileName, 0, true, 5,
          "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false,
          0, true); 
     Excel.Sheets sheets = theWorkbook.Worksheets;
     Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);
     System.Array myvalues;
     Excel.Range range = worksheet.get_Range("A1", "E1".ToString());
     myvalues = (System.Array)range.Cells.Value;

重要的!您应该释放使用的资源。从这里

// Need all following code to clean up and extingush all references!!!
theWorkbook.Close(null,null,null);
xl.Workbooks.Close();
xl.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject (range);
System.Runtime.InteropServices.Marshal.ReleaseComObject (sheets);
System.Runtime.InteropServices.Marshal.ReleaseComObject (xl);
System.Runtime.InteropServices.Marshal.ReleaseComObject (worksheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject (theWorkbook);
worksheet=null;
sheets=null;
theWorkbook=null;
xl = null;
GC.Collect(); // force final cleanup!
于 2009-11-09T08:29:56.640 回答
0

SpreadsheetGear for .NET可以读取、写入、计算等... Excel 工作簿,并允许您使用 IWorksheet 等 API 访问任何单元格的基础数据(数字、文本、逻辑、错误)或任何单元格的格式化文本。 Cells[rowIndex, colIndex].Value 或 IWorksheet.Cells[rowIndex, colIndex].Text。每列/单元格中的数据类型没有限制。SpreadsheetGear 是 100% 安全的 .NET 代码(没有 COM 互操作,没有不安全的本机调用等),因此它比其他选项更容易部署 - 特别是在服务器场景中。

您可以在此处查看实时样本并此处下载免费试用版。

免责声明:我拥有 SpreadsheetGear LLC

于 2009-11-09T20:53:04.683 回答
0

当其他一切都失败时,这就是我所做的......从excel导入时,我HDR = NO在连接字符串中指定。这将标题作为第一行导入,从而使所有列数据类型为文本。之后是一个简单的函数来提及数据表的列名。类似于下面的代码...

private DataTable NameHeaderRows(DataTable dt)
{
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        dt.Columns[i].ColumnName = dt.Rows[0][i].ToString();

    }
    dt.Rows.RemoveAt(0);
    return dt;
}

我知道这很乏味,但没有找到任何可行的解决方案。欢迎任何其他建议。

于 2013-06-20T11:39:07.717 回答