C#中CSV文件与DataTable互相导入导出代码实例

阿澈
阿澈
发布时间:2026-10-14 | 2人浏览过
原创

在实际的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#数据处理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表