我有一个从 Excel 导入数据然后处理它的 C#/.Net 作业。我们的客户放下文件,我们处理它们。我对原始文件没有任何控制权。
我使用 OleDb 库来填充数据集。该文件包含一些数字,如 30829300、30071500 等……这些列的数据类型是“文本”。
当我导入数据时,这些数字会转换为科学计数法。有没有办法防止这种情况发生?
此问题的一种解决方法是更改您的 select 语句,而不是 SELECT * 这样做:
"SELECT Format([F1], 'General Number') From [Sheet1$]"
-or-
"SELECT Format([F1], \"#####\") From [Sheet1$]"
但是,如果您的单元格包含超过 255 个字符并出现以下错误,这样做会崩溃:“多步 OLE DB 操作生成错误。检查每个 OLE DB 状态值(如果可用)。没有完成任何工作。”
幸运的是,我的客户并不关心在这种情况下出错。
这个页面也有很多好东西可以尝试: http ://www.dicks-blog.com/archives/2004/06/03/external-data-mixed-data-types/
OleDb 库通常会在 Excel 电子表格中弄乱您的数据。这主要是因为它强制所有内容进入固定类型的列布局,从每列的前 8 个单元格中的值猜测每列的类型。如果它猜错了,你最终会将数字字符串转换为科学记数法。布莱赫!
为避免这种情况,您最好跳过 OleDb 并自己直接阅读工作表。您可以使用 Excel 的 COM 接口(也是 blech!)或第三方 .NET Excel 兼容阅读器来执行此操作。 SpreadsheetGear就是这样一个运行良好的库,并且具有与 Excel 的 COM 接口非常相似的接口。
使用此连接字符串:
Provider=Microsoft.ACE.OLEDB.12.0; data source={0}; Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1\"
使用 Excel 2010,我注意到以下内容。如果在您运行 OLEDB SELECT 时 Excel 文件已打开,那么您将获得当前版本的单元格,而不是保存的文件值。此外,为长数字、十进制值和日期返回的字符串值如下所示:
5.0130370071e+012
4.08
36808
如果文件未打开,则返回值为:
5013037007084
£4.08
Monday, October 09, 2000
如果您使用 Open XML SDK 2.0 Productivity Tool 查看实际的 .XSLX 文件(或简单地解压缩文件并在记事本中查看 XML),您将看到 Excel 2007 实际上以科学格式存储原始数据。
例如 0.00001 存储为 1.0000000000000001E-5
<x:c r="C18" s="11" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:v>1.0000000000000001E-5</x:v>
</x:c>
查看 Excel 中的单元格,其在单元格和编辑栏中均显示为 0.00001。因此,OleDB 导致问题并不总是正确的。
我发现最简单的方法是为具有大“数字”的列选择 Zip 格式,而不是文本格式。
您是否尝试在阅读时将该字段的值转换为 (int) 或 (Int64)?
在 google 上查找 IMEX=1 连接字符串选项和 TypeGuessRows 注册表设置。事实上,没有简单的方法来解决这个问题,因为读者通过查看前几行(默认为 8 行)来推断列数据类型。如果行包含所有数字,那么你就不走运了。
我过去使用的一个不幸的解决方法是使用 HDR=NO 连接字符串选项并将 TypeGuessRows 注册表设置值设置为 1,这会强制它读取第一行作为有效数据来确定其数据类型,而不是一个标题。这是一个黑客,但它的工作原理。代码将第一行(包含标题)读取为文本,然后相应地设置数据类型。
更改注册表是一件痛苦的事情(并不总是可能),但我建议之后恢复原始值。
如果您的导入数据没有标题行,那么另一种选择是预处理文件并在违规列中的每个数字之前插入一个 ' 字符。这会导致列数据被视为文本。
所以总而言之,有很多黑客可以解决这个问题,但没有什么是万无一失的。
我遇到了同样的问题,但无需借助 Excel COM 接口或第 3 方软件即可解决此问题。它涉及一些处理开销,但似乎对我有用。
这是一些说明这一点的代码,作为额外的奖励,它甚至是 StyleCopped!
public void ImportSpreadsheet(string path)
{
string extendedProperties = "Excel 12.0;HDR=YES;IMEX=1";
string connectionString = string.Format(
CultureInfo.CurrentCulture,
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"{1}\"",
path,
extendedProperties);
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
using (OleDbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM [Worksheet1$]";
connection.Open();
using (OleDbDataAdapter adapter = new OleDbDataAdapter(command))
using (DataSet columnDataSet = new DataSet())
using (DataSet dataSet = new DataSet())
{
columnDataSet.Locale = CultureInfo.CurrentCulture;
adapter.Fill(columnDataSet);
if (columnDataSet.Tables.Count == 1)
{
var worksheet = columnDataSet.Tables[0];
// Now that we have a valid worksheet read in, with column names, we can create a
// new DataSet with a table that has preset columns that are all of type string.
// This fixes a problem where the OLEDB provider is trying to guess the data types
// of the cells and strange data appears, such as scientific notation on some cells.
dataSet.Tables.Add("WorksheetData");
DataTable tempTable = dataSet.Tables[0];
foreach (DataColumn column in worksheet.Columns)
{
tempTable.Columns.Add(column.ColumnName, typeof(string));
}
adapter.Fill(dataSet, "WorksheetData");
if (dataSet.Tables.Count == 1)
{
worksheet = dataSet.Tables[0];
foreach (var row in worksheet.Rows)
{
// TODO: Consume some data.
}
}
}
}
}
}
}
我从其他地方得到了一个解决方案,但它对我来说非常有效。无需更改任何代码,只需将 excel 列单元格格式设置为“常规”而不是“数字”或“文本”等任何其他格式,然后甚至 Select * from [$Sheet1] 或 Select Column_name from [$Sheet1] 将读取即使是超过 9 位的大数值,它也很完美
我在这个州周围搜索了一下。这是我的解决步骤
1 格式 Excel 列作为文本 2 编写宏以禁用数字 -> 文本转换的错误警告
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.ErrorCheckingOptions.BackgroundChecking = Ture
End Sub
Private Sub Workbook_Open()
Application.ErrorCheckingOptions.BackgroundChecking = False
End Sub
3-在读取要导入的数据时,尝试将传入的数据解析为 Int64 或 Int32 ....