尝试通过 Microsoft.ACE.OLEDB 驱动程序读取 xlsx 信息时出现未指定错误
Unspecified Error when trying to read xlsx info via Microsoft.ACE.OLEDB driver
我有一个应用程序已从 Visual Studio 2010(运行 on Windows Server 2003)升级到 Visual Studio 2013(现在 运行 on Windows 服务器 2008)。该应用程序的一个方面允许用户将 xlsx
sheet 上传到文件夹,然后脚本会验证其内容。
我有这个方法:
Private Function GetValuesFromExcel(ByVal strFileIn As String) As DataSet
Dim ds As DataSet = New DataSet
Dim strConn As String = ""
Try
If strFileIn.ToLower().EndsWith(".xlsx") Then
'This one is good for files that are saved with Excel
strConn = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" + strFileIn + "'; Extended Properties=Excel 12.0 Xml;"
Else
strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source='" + strFileIn + "'; Extended Properties=Excel 8.0;"
End If
Dim conn = New OleDb.OleDbConnection(strConn)
conn.Open()
Dim dtExcelTables As DataTable = conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "TABLE"})
Dim strExcel As String = "select * from [" + dtExcelTables.Rows(0)("TABLE_NAME").ToString() + "]"
Dim myCommand = New OleDb.OleDbDataAdapter(strExcel, strConn)
myCommand.TableMappings.Add("Table", "table1")
'myCommand.Fill(ds, "table1")
myCommand.Fill(ds)
conn.Close()
Catch ex As Exception
DBUtils.WriteToLog("Error", "GetValuesFromExcel", ex.Message, Security.GetCurrentUser())
Throw ex
End Try
Return ds
End Function
在 conn.Open()
上,它抛出一个错误。具体来说,最优秀的错误,"Unspecified Error"。很有帮助。
我们使用的是 Office 2007,我已检查以确保确实安装了 32 位 Access 数据库引擎可再发行组件。
到底是什么问题?
我会稍微讨论一下,你不太可能得到 "push this button to solve your problem" 答案。
您得到的错误是 E_FAIL
,一个通用的 COM 错误代码。当 Microsoft 软件无法正确猜测失败的根本原因时,通常会使用它。猜测更具体的一个太冒险了,会让他们的客户陷入困境。这是一般 COM 的责任,它不直接支持异常,只支持错误代码。因此,丢失的一个主要功能是堆栈跟踪,这是一个提示,可以提供有关检测到错误的特定层的大量信息。
对付它们的唯一真正方法是通过消除过程。这在这里是可行的,代码很早就失败了。您唯一可能做错的事情是提供错误的连接字符串、提供错误的数据或 运行 在错误的执行上下文中执行代码。剔除常见错误:
- 错误的连接字符串语法。不是你的问题。
- 文件路径无效。不是你的问题,产生了一个好消息
- 文件实际上不是 Excel 文件。不是你的问题,产生了一个好消息
- 尝试在 64 位进程中运行。不是你的问题,好消息。
不容易消除的不太常见的错误:
- 将 运行s 编程为具有可访问性问题的帐户的服务。通过使用一个小的控制台模式应用程序对其进行测试来消除它。
- 该文件是一个 .xlsx 文件,但它已轻微损坏。通过使用一组其他 .xlsx 文件进行测试来消除它。
最可能的原因是:
- OleDb 提供程序未正确安装。通常也是 Microsoft 代码因 E_FAIL 等一般错误而放弃的常见原因。当然很难诊断,您 可能 通过使用 SysInternals 的 Process Monitor 并将好的跟踪与坏的跟踪进行比较来找到某个地方。很高兴发现丢失的文件或注册表项。请记住,在 安装 Office 之后安装 32 位 Access Database Engine 可再发行组件 并不是一个好主意,它只能在没有 Office 的机器上使用。您至少需要旋转一次幸运轮的重新安装轮。
也许苦难也是放弃这些提供者的一个很好的理由。 EPPlus library 获得了很好的评价,在服务器上的扩展性也很好。
我赞同 Hans 的想法,即可能放弃这些提供商并寻找替代方案。
我最近遇到了与您面临的问题类似的问题。我开发了一个在我的机器上运行良好的解决方案,但由于没有安装必要的驱动程序而在其他机器上运行良好。
我的情况是将安装在客户端计算机上的 Winforms 应用程序,我无法控制安装了哪些外部提供程序(ACE、JET 等)。我们也不知道他们安装了哪些版本的 Office。要么我们提供了一个复杂的解决方案,能够使用安装的任何驱动程序……要么寻找替代方案。
我们选择了后者,并选择了Excel Data Reader。大约 30 分钟后,该解决方案现在可以运行,而不依赖于它部署到的机器的配置。
我的代码需要简单地将数据从 Excel 文件(从 SSRS 报告生成)读取到内存中的 DataTable 中以进行一些数据比较。我们最终采用的方法表明实现起来是多么简单;
/// <summary>
/// Read data from MS Excel saved as an export from their SSRS reports.
/// This method uses ExcelDataReader <link>https://github.com/ExcelDataReader/ExcelDataReader</link>
/// to avoid dependencies on OleDb Jet or ACE drivers. Given we can't control what is installed on
/// client machines, we can't assume they'll have the correct drivers installed, and therefore we'll
/// make use of ExcelDataReader.
/// </summary>
/// <param name="filename">Filename to the path of the Excel (xls or xlsx) file.</param>
/// <returns>DataTable containing the required data or null if no data is found.</returns>
private DataTable ReadDataFromUsingExcelReader(string filename)
{
DataTable returnval = null;
DataSet result = null;
using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
if (filename.EndsWith("xls", StringComparison.OrdinalIgnoreCase))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream))
{
result = excelReader.AsDataSet();
}
}
else if (filename.EndsWith("xlsx", StringComparison.OrdinalIgnoreCase))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream))
{
result = excelReader.AsDataSet();
}
}
}
returnval = result != null && result.Tables[0] != null ? result.Tables[0].Copy() : null;
return returnval;
}
好的,所以我解决了与我的情况有关的问题...我坚持使用 ACE.OLEDB 驱动程序,因为我知道我可以让它们在这种情况下工作。另外,我认为这是愚蠢而小的事情。是的。
xlsx sheet 被写入名为 'admin->excel_uploads' 的文件夹中。原来我在我的配置文件中将 identity impersonate 设置为 true。我 运行 所在的服务帐户没有完整的 read/write 权限。这解决了为什么它不能在本地工作,因为一旦我关闭模拟,它就很好用了。然后在部署时,我只需要为我 运行 所在的服务帐户设置权限。
我有一个应用程序已从 Visual Studio 2010(运行 on Windows Server 2003)升级到 Visual Studio 2013(现在 运行 on Windows 服务器 2008)。该应用程序的一个方面允许用户将 xlsx
sheet 上传到文件夹,然后脚本会验证其内容。
我有这个方法:
Private Function GetValuesFromExcel(ByVal strFileIn As String) As DataSet
Dim ds As DataSet = New DataSet
Dim strConn As String = ""
Try
If strFileIn.ToLower().EndsWith(".xlsx") Then
'This one is good for files that are saved with Excel
strConn = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" + strFileIn + "'; Extended Properties=Excel 12.0 Xml;"
Else
strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source='" + strFileIn + "'; Extended Properties=Excel 8.0;"
End If
Dim conn = New OleDb.OleDbConnection(strConn)
conn.Open()
Dim dtExcelTables As DataTable = conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "TABLE"})
Dim strExcel As String = "select * from [" + dtExcelTables.Rows(0)("TABLE_NAME").ToString() + "]"
Dim myCommand = New OleDb.OleDbDataAdapter(strExcel, strConn)
myCommand.TableMappings.Add("Table", "table1")
'myCommand.Fill(ds, "table1")
myCommand.Fill(ds)
conn.Close()
Catch ex As Exception
DBUtils.WriteToLog("Error", "GetValuesFromExcel", ex.Message, Security.GetCurrentUser())
Throw ex
End Try
Return ds
End Function
在 conn.Open()
上,它抛出一个错误。具体来说,最优秀的错误,"Unspecified Error"。很有帮助。
我们使用的是 Office 2007,我已检查以确保确实安装了 32 位 Access 数据库引擎可再发行组件。
到底是什么问题?
我会稍微讨论一下,你不太可能得到 "push this button to solve your problem" 答案。
您得到的错误是 E_FAIL
,一个通用的 COM 错误代码。当 Microsoft 软件无法正确猜测失败的根本原因时,通常会使用它。猜测更具体的一个太冒险了,会让他们的客户陷入困境。这是一般 COM 的责任,它不直接支持异常,只支持错误代码。因此,丢失的一个主要功能是堆栈跟踪,这是一个提示,可以提供有关检测到错误的特定层的大量信息。
对付它们的唯一真正方法是通过消除过程。这在这里是可行的,代码很早就失败了。您唯一可能做错的事情是提供错误的连接字符串、提供错误的数据或 运行 在错误的执行上下文中执行代码。剔除常见错误:
- 错误的连接字符串语法。不是你的问题。
- 文件路径无效。不是你的问题,产生了一个好消息
- 文件实际上不是 Excel 文件。不是你的问题,产生了一个好消息
- 尝试在 64 位进程中运行。不是你的问题,好消息。
不容易消除的不太常见的错误:
- 将 运行s 编程为具有可访问性问题的帐户的服务。通过使用一个小的控制台模式应用程序对其进行测试来消除它。
- 该文件是一个 .xlsx 文件,但它已轻微损坏。通过使用一组其他 .xlsx 文件进行测试来消除它。
最可能的原因是:
- OleDb 提供程序未正确安装。通常也是 Microsoft 代码因 E_FAIL 等一般错误而放弃的常见原因。当然很难诊断,您 可能 通过使用 SysInternals 的 Process Monitor 并将好的跟踪与坏的跟踪进行比较来找到某个地方。很高兴发现丢失的文件或注册表项。请记住,在 安装 Office 之后安装 32 位 Access Database Engine 可再发行组件 并不是一个好主意,它只能在没有 Office 的机器上使用。您至少需要旋转一次幸运轮的重新安装轮。
也许苦难也是放弃这些提供者的一个很好的理由。 EPPlus library 获得了很好的评价,在服务器上的扩展性也很好。
我赞同 Hans 的想法,即可能放弃这些提供商并寻找替代方案。
我最近遇到了与您面临的问题类似的问题。我开发了一个在我的机器上运行良好的解决方案,但由于没有安装必要的驱动程序而在其他机器上运行良好。
我的情况是将安装在客户端计算机上的 Winforms 应用程序,我无法控制安装了哪些外部提供程序(ACE、JET 等)。我们也不知道他们安装了哪些版本的 Office。要么我们提供了一个复杂的解决方案,能够使用安装的任何驱动程序……要么寻找替代方案。
我们选择了后者,并选择了Excel Data Reader。大约 30 分钟后,该解决方案现在可以运行,而不依赖于它部署到的机器的配置。
我的代码需要简单地将数据从 Excel 文件(从 SSRS 报告生成)读取到内存中的 DataTable 中以进行一些数据比较。我们最终采用的方法表明实现起来是多么简单;
/// <summary>
/// Read data from MS Excel saved as an export from their SSRS reports.
/// This method uses ExcelDataReader <link>https://github.com/ExcelDataReader/ExcelDataReader</link>
/// to avoid dependencies on OleDb Jet or ACE drivers. Given we can't control what is installed on
/// client machines, we can't assume they'll have the correct drivers installed, and therefore we'll
/// make use of ExcelDataReader.
/// </summary>
/// <param name="filename">Filename to the path of the Excel (xls or xlsx) file.</param>
/// <returns>DataTable containing the required data or null if no data is found.</returns>
private DataTable ReadDataFromUsingExcelReader(string filename)
{
DataTable returnval = null;
DataSet result = null;
using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
if (filename.EndsWith("xls", StringComparison.OrdinalIgnoreCase))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream))
{
result = excelReader.AsDataSet();
}
}
else if (filename.EndsWith("xlsx", StringComparison.OrdinalIgnoreCase))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream))
{
result = excelReader.AsDataSet();
}
}
}
returnval = result != null && result.Tables[0] != null ? result.Tables[0].Copy() : null;
return returnval;
}
好的,所以我解决了与我的情况有关的问题...我坚持使用 ACE.OLEDB 驱动程序,因为我知道我可以让它们在这种情况下工作。另外,我认为这是愚蠢而小的事情。是的。
xlsx sheet 被写入名为 'admin->excel_uploads' 的文件夹中。原来我在我的配置文件中将 identity impersonate 设置为 true。我 运行 所在的服务帐户没有完整的 read/write 权限。这解决了为什么它不能在本地工作,因为一旦我关闭模拟,它就很好用了。然后在部署时,我只需要为我 运行 所在的服务帐户设置权限。