C#中CSV文件与DataTable互相导入导出代码实例
在实际的C#开发中,经常需要处理CSV格式的数据交换。本文详细介绍如何利用扩展方法实现DataTable到CSV文件的导出,以及从CSV文件读取数据追加到DataTable的功能。代码包含必要的参数校验与异常处理,可直接集成至现有项目中。
核心逻辑说明
本方案主要解决两个问题:一是将内存中的DataTable对象序列化为标准的UTF-8编码CSV文本;二是解析CSV文本并将特定起始行的数据还原为DataTable的行记录。核心依赖System.Data和System.IO命名空间,并通过静态扩展方法提供便捷调用。
准备条件与环境要求
在进行代码集成前,请确保项目已引用以下基础命名空间:
System:用于基本类型与字符串操作。System.Data:用于DataTable与DataRow对象管理。System.IO:用于文件流的读写控制。System.Text:用于字符集(如UTF-8)的定义。
第1步:实现数据导出(DataTable to CSV)
此步骤旨在将现有的DataTable内容保存为本地CSV文件。操作中需特别注意路径合法性检查与编码格式设定。
- 目的:将内存数据持久化存储,便于外部系统读取或存档。
- 关键参数:
fullSavePath(完整文件路径)、tableheader(文件头信息)、columname(列名标题)。 - 动作流程:首先校验参数非空且路径合法;接着创建
StreamWriter并指定UTF-8编码;随后依次写入文件头、列名及逐行数据。
第2步:实现数据导入(CSV to DataTable)
此步骤负责将磁盘上的CSV文件解析,并从指定行数开始将数据追加至DataTable。
- 目的:从外部源加载结构化数据。
- 关键参数:
filePath(文件路径)、rowIndex(开始读取的行索引,从0开始计)。 - 动作流程:使用
StreamReader逐行读取;跳过索引小于rowIndex的行;对剩余行使用逗号分割符拆分字符串,并赋值给新建的DataRow,最后添加回原表。
完整工具类代码实现
以下代码实现了上述逻辑,包含了健壮性的参数检查。可直接复制到项目的工具类库中使用。
using System;
using System.Data;
using System.IO;
using System.Text;
namespace DBUtilHelpV2Plus
{
public static class DBToolV2Plus
{
/// <summary>
/// 将DataTable导出到CSV.
/// </summary>
/// <param name="table">DataTable</param>
/// <param name="fullSavePath">保存路径</param>
/// <param name="tableheader">标题信息</param>
/// <param name="columname">列名称『eg:姓名,年龄』</param>
/// <returns>导出成功true;导出失败false</returns>
public static bool ToCSV(this DataTable table, string fullSavePath, string tableheader, string columname)
{
ArgumentChecked(table, fullSavePath);
//------------------------------------------------------------------------------------
try
{
string _bufferLine = "";
using (StreamWriter _writerObj = new StreamWriter(fullSavePath, false, Encoding.UTF8))
{
if (!string.IsNullOrEmpty(tableheader))
_writerObj.WriteLine(tableheader);
if (!string.IsNullOrEmpty(columname))
_writerObj.WriteLine(columname);
for (int i = 0; i < table.Rows.Count; i++)
{
_bufferLine = "";
for (int j = 0; j < table.Columns.Count; j++)
{
if (j > 0)
_bufferLine += ",";
_bufferLine += table.Rows[i][j].ToString();
}
_writerObj.WriteLine(_bufferLine);
}
return true;
}
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 参数检查
/// </summary>
private static void ArgumentChecked(DataTable table, string filePath)
{
if (table == null)
throw new ArgumentNullException("table");
if (string.IsNullOrEmpty(filePath))
throw new ArgumentNullException("filePath");
// 注意:此处假设存在自定义的工具方法 CSharpToolV2.GetFileNameOnly
// 若编译报错,可替换为 Path.GetFileName(filePath)
string _fileName = System.IO.Path.GetFileName(filePath);
if (string.IsNullOrEmpty(_fileName))
throw new ArgumentException(string.Format("参数filePath的值{0},不是正确的文件路径!", filePath));
}
/// <summary>
/// 将CSV文件数据导入到Datable中
/// </summary>
/// <param name="table">目标DataTable</param>
/// <param name="filePath">文件路径</param>
/// <param name="rowIndex">开始读取的行索引</param>
/// <returns>更新后的DataTable</returns>
public static DataTable AppendCSVRecord(this DataTable table, string filePath, int rowIndex)
{
ArgumentChecked(table, filePath);
if (rowIndex < 0)
throw new ArgumentException("rowIndex must be >= 0");
using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8, false))
{
int i = 0, j = 0;
while (!reader.EndOfStream)
{
j++;
string _line = reader.ReadLine();
if (j >= rowIndex + 1)
{
// 简单按逗号分割,实际场景中需注意字段内含逗号的情况
string[] _split = _line.Split(',');
DataRow _row = table.NewRow();
for (i = 0; i < _split.Length && i < table.Columns.Count; i++)
{
_row[i] = _split[i];
}
table.Rows.Add(_row);
}
}
return table;
}
}
}
}
测试用例与运行验证
为了验证上述功能的有效性,下面提供一个控制台程序的测试示例。该示例动态生成模拟数据,执行导出后清空再导入,并输出最终结果。
using System;
using System.Data;
namespace DBUtilHelpV2PlusTest
{
class Program
{
static DataTable testDb = null;
// 生成带时间戳的文件名以避免覆盖
static string fullSavePath = string.Format(@"C:\{0}.csv", DateTime.Now.ToString("yyyyMMddHHmmss"));
static void Main(string[] args)
{
try
{
CreateTestDb();
Console.WriteLine(string.Format("DataTable导出到CSV文件{0}.", testDb.ToCSV(fullSavePath, "姓名,年龄", "人员信息表") ? "成功" : "失败"));
// 清空原有内存数据,用于演示重新导入
testDb.Rows.Clear();
Console.WriteLine(string.Format("清空数据,当前{0}条数据.", testDb.Rows.Count));
// 从第2行开始导入(即跳过表头和第一行列名)
testDb = testDb.AppendCSVRecord(fullSavePath, 2);
Console.WriteLine(string.Format("CSV文件导入到Datable,导入{0}条数据.", testDb.Rows.Count));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}
}
static void CreateTestDb()
{
if (testDb == null)
{
// 初始化表结构:Name为字符串,Age为整数
testDb = new DataTable();
testDb.Columns.Add("Name", typeof(string));
testDb.Columns.Add("Age", typeof(int));
// 填充10条测试数据
for (int i = 1; i <= 10; i++)
{
DataRow _row = testDb.NewRow();
_row["Name"] = string.Format("YanZhiwei_{0}", i);
_row["Age"] = i;
testDb.Rows.Add(_row);
}
}
}
}
}
上述代码执行后,将在控制台打印导出状态、清空确认信息及导入的数据条数。生成的CSV文件结构应如下所示:
导入后的DataTable数据结构与原始一致。运行效果如下图所示:
注意事项与排错
- 特殊字符处理:上述CSV导出并未处理单元格内部包含逗号或换行符的情况。若业务数据复杂,建议引入成熟的CSV库(如CsvHelper)进行序列化。
- 文件锁定:如果同一进程频繁访问该CSV文件,请确保在写入完成后释放流或等待足够的时间间隔,避免文件被占用导致读取失败。
- 编码一致性:确保写入和读取时均使用相同的编码格式(默认为UTF-8),否则可能出现中文乱码。
总结
通过扩展方法,我们可以非常简洁地在C#中实现DataTable与CSV之间的互转。这种轻量级的方案适合小规模数据的快速传输与交换。以上就是C#中CSV文件与DataTable互相导入处理实例解析的详细内容,更多关于C#数据处理的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









