ExcelDataReader比Interop更稳定,因无Office依赖;读取后应批量用SqlBulkCopy写入,注意编码、CSV解析、列对齐、空值处理及错误捕获。

用 ExcelDataReader 读 Excel 比 Microsoft.Office.Interop.Excel 更稳
Interop 依赖本地 Office 安装,服务器上基本跑不起来,还会卡死进程;ExcelDataReader 是纯 .NET 库,支持 .xls 和 .xlsx,无外部依赖。
- 安装 NuGet 包:
Install-Package ExcelDataReader(记得加DataTables扩展包,方便转DataTable) - 读取后别直接 foreach 行插入——每行一次 DB 写入太慢,攒够 100–500 行再用
SqlBulkCopy批量进 SQL Server - 注意编码:.xlsx 默认 UTF-8,但有些用户导出的 Excel 实际是 ANSI 编码,
ExcelDataReader会报InvalidDataException;可先用FileStream检查 BOM 判断编码,或统一用ExcelDataSetConfiguration配置UseStream+ReadAsDataSet
StreamReader + TextFieldParser 处理 CSV 更可靠
别用 string.Split(',') 解析 CSV——字段含逗号、换行、引号时必崩;Microsoft.VisualBasic.FileIO.TextFieldParser 是 .NET 内置方案,比第三方库轻,且能自动处理转义和引号包裹。
- 必须设
HasFieldsEnclosedInQuotes = true,否则"Smith, John"会被切两段 - CSV 文件没表头?用
SetDelimiters(",")后调ReadFields()前先ReadLine()跳过首行,或手动指定列名数组传给DataTable.Columns.Add() - 中文乱码常见于 ANSI(GBK)编码的 CSV:构造
TextFieldParser时传new StreamReader(path, Encoding.GetEncoding("GB2312")),别依赖默认UTF8
SqlBulkCopy 写数据库前必须对齐列名和类型
列顺序错位、类型不匹配、空值没设 AllowDBNull = true,都会让 SqlBulkCopy.WriteToServer() 报 InvalidOperationException 或静默丢数据。
-
DataTable的列名必须和目标表字段名**完全一致**(大小写敏感取决于 SQL Server 排序规则),别指望自动映射 - 日期字段如果 Excel/CSV 里是空字符串,
DataTable对应列类型设成typeof(DateTime?),并确保该列AllowDBNull = true - 批量写入前加
bulkCopy.BatchSize = 10000,避免单次内存暴涨;超大文件分批次读+写,别把整个 CSV 全 load 进内存再 bulk
导入失败时,错误信息往往藏在 SqlRowsCopied 和 SqlBulkCopy 的异常堆栈里
不是所有失败都会抛异常——比如目标列长度不够,SQL Server 可能截断后静默写入,也可能报 String or binary data would be truncated,但这个错误只在 SqlBulkCopy 完成后才暴露。
- 务必订阅
SqlBulkCopy.SqlRowsCopied事件,实时打印已写入行数,中断时能知道卡在哪一批 - 捕获
SqlException后检查Number字段:4801是权限不足,2627是主键冲突,8152是字段超长——不同数字对应不同修复方向 - 开发阶段加
bulkCopy.EnableStreaming = true并配合DataTable的Load()方法从流读取,避免内存溢出导致 OOM 被系统杀掉
实际做导入时,最麻烦的从来不是读文件或写库,而是 Excel 里有人手输了个空格在日期栏、CSV 用 Excel 另存时偷偷改了编码、或者数据库字段允许 NULL 但代码里没设 AllowDBNull。这些点不提前盯住,日志里只有一行“写入失败”,就得一行行比对原始数据。











