使用Microsoft ACE OLEDB驱动时,CSV与Excel的数据类型检测行为不一致,如何解决?
问题说明
Microsoft.ACE.OLEDB.12.0驱动在检测CSV文件的混合类型列时存在类型推断错误,具体表现如下:
示例混合类型列:
Value ----- 24 200 AM1 AM2 55 22
不同文件类型的对比结果
读取Excel文件时:
使用连接字符串:Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dataSource};Persist Security Info=False;Extended Properties="Excel 12.0 Xml;HDR=YES"通过以下代码获取架构信息,
ColumnDataType能正确返回System.String:DbDataReader reader = command.ExecuteReader(CommandBehavior.SchemaOnly); DataTable schemaTable = reader.GetSchemaTable(); reader.Close(); foreach (DataRow r in schemaTable.Rows) { new { ColumnName = r["ColumnName"].ToString(), ColumnDataType = r["DataType"].ToString(), ColumnOrdinal = (int)r["ColumnOrdinal"], ColumnSize = (int)r["ColumnSize"] }; }读取CSV文件时:
使用连接字符串:Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dataSource};Persist Security Info=False;Extended Properties="text;HDR=YES;FMT=Delimited"对应的
schema.ini内容:[file.csv] Format=Delimited(,) ColNameHeader=True DateTimeFormat=yyyy-mm-dd hh:nn:ss DecimalSymbol=. CharacterSet=65001此时
ColumnDataType始终返回System.Int32,导致后续基于架构的操作出错。已尝试修改CharacterSet为OEM/ANSI、添加IMEX=1,均无效。
原因分析
这是ACE OLEDB驱动处理CSV文件的内置行为限制:驱动默认采样文件前8行推断列类型,当采样行中数值类型占多数时,就会将列判定为数值型,忽略后续出现的字符串值。而Excel文件的处理逻辑不同,驱动能更准确识别混合类型并标记为字符串。
解决办法
在schema.ini中显式指定列类型
这是最可靠的方案,直接强制驱动按指定类型读取列。修改schema.ini,添加ColX字段明确指定列类型为Char或Memo:[file.csv] Format=Delimited(,) ColNameHeader=True DateTimeFormat=yyyy-mm-dd hh:nn:ss DecimalSymbol=. CharacterSet=65001 Col1=Value Char(255) # 用Memo类型可适配更长字符串注意
Col1对应第一列,列名需与CSV表头一致,类型设置为Char(n)或Memo即可强制识别为字符串。调整驱动采样行数(仅部分场景适用)
修改注册表中ACE驱动的采样行数,将默认的8行改为更大数值(或0表示扫描所有行),但此方法需要管理员权限,且对系统全局生效,不推荐多环境场景使用:- 32位系统:
HKEY_LOCAL_MACHINE\Software\Microsoft\Jet\4.0\Engines\Text\ScanRows - 64位系统:
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Jet\4.0\Engines\Text\ScanRows
将ScanRows的值改为0或所需行数。
- 32位系统:
切换至专门的CSV读取库
若ACE驱动的限制无法满足需求,可改用CsvHelper、FileHelpers等专门的CSV处理库,这类库能更灵活处理混合类型列,无需依赖OLEDB驱动的自动类型推断。
内容的提问来源于stack exchange,提问作者Francis Ducharme

