CSV(Comma-Separated Values)是数据交换中最常用的格式之一。在.NET开发中,将CSV数据加载到DataTable对象中可以方便地进行数据绑定、查询和操作。本文将介绍几种主流实现方案及其适用场景。
一、方案对比概览
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| OleDb + Microsoft.Jet/ACE | 无需第三方库,SQL式操作 | 需要安装驱动,大数据量性能差 | 简单查询、快速原型 |
| Microsoft.VisualBasic.FileIO | 内置支持,代码简洁 | 功能较基础,灵活性有限 | 标准格式CSV、无需复杂处理 |
| CsvHelper (第三方库) | 功能强大,性能优异,支持映射 | 需要NuGet引用 | 复杂业务对象、大数据量 |
| 手动解析 (StreamReader) | 零依赖,完全可控 | 代码量大,需处理各种边界情况 | 特殊格式、学习目的 |
二、代码实现
本文主要是使用手动解析方式,实现CSV文件数据读取。
harppublicstaticDataTableReadDataTable(stringfilePath){DataTabledt=newDataTable();try{System.Text.Encodingencoding=Encoding.Default;//GetType(filePath); //// DataTable dt = new DataTable();System.IO.FileStreamfs=newSystem.IO.FileStream(filePath,System.IO.FileMode.Open,System.IO.FileAccess.Read);System.IO.StreamReadersr=newSystem.IO.StreamReader(fs,encoding);//记录每次读取的一行记录stringstrLine="";//记录每行记录中的各字段内容string[]aryLine=null;string[]tableHead=null;//标示列数intcolumnCount=0;//标示是否是读取的第一行boolIsFirst=true;//逐行读取CSV中的数据while((strLine=sr.ReadLine())!=null){if(IsFirst==true){tableHead=strLine.Split(',');IsFirst=false;columnCount=tableHead.Length;//创建列for(inti=0;i<columnCount;i++){DataColumndc=newDataColumn(tableHead[i]);dt.Columns.Add(dc);}}else{aryLine=strLine.Split(',');DataRowdr=dt.NewRow();for(intj=0;j<columnCount;j++){dr[j]=aryLine[j];}dt.Rows.Add(dr);}}if(aryLine!=null&&aryLine.Length>0){dt.DefaultView.Sort=tableHead[0]+" "+"asc";}sr.Close();fs.Close();}catch(Exceptionex){}returndt;}三、DataTable 性能优化建议
当处理大文件(>100MB)时,直接加载到DataTable可能导致内存溢出:
| 优化策略 | 实现方式 |
|---|---|
| 分页加载 | 使用CsvReader的SkipRecords配合Take |
| 只读模式 | dataTable.DefaultView.ReadOnly = true |
| 列类型指定 | 显式设置DataColumn.DataType,避免装箱拆箱 |
| 批量插入 | 使用SqlBulkCopy直接入库,不经过DataTable |
四、常见问题与解决方案
Q1: 中文乱码问题
原因:CSV文件保存编码与读取编码不一致。
解决:统一使用UTF-8 with BOM或明确指定编码:
// CsvHelper 配置varconfig=newCsvConfiguration(CultureInfo.InvariantCulture){Encoding=Encoding.UTF8,// 关键设置HasHeaderRecord=true};Q2: 日期格式解析失败
解决:使用TypeConverter或指定格式:
// 全局配置config.TypeConverterCache.AddConverter<DateTime>(newDateTimeConverter("yyyy-MM-dd HH:mm:ss"));Q3: 数据类型转换异常
解决:先创建带类型的DataTable列,而非默认string:
dataTable.Columns.Add("Id",typeof(int));dataTable.Columns.Add("Price",typeof(decimal));dataTable.Columns.Add("IsActive",typeof(bool));// 读取时使用 SetField 而非 Add(string)