C#操作CSV文件的详细教程

 更新时间:2026年01月23日 09:17:41   作者:工程师007  
文章详细介绍了CSV文件的格式、读取和写入多种方式,包括使用StreamReader、TextFieldParser、CsvHelper库等,同时,还讨论了处理特殊字符、将CSV数据映射到对象以及注意事项,如文件路径和数据类型转换,并提到了性能优化的方法,需要的朋友可以参考下

一、CSV 格式详解

基本语法

  • CSV 文件以纯文本形式存储数据,每一行代表一条记录。
  • 字段之间以逗号(,)分隔,例如:姓名,年龄,性别
  • 如果字段中包含逗号、双引号(")或换行符,需要用双引号将字段包围起来。如果字段本身包含双引号,则需要用两个双引号表示一个双引号。例如:"张三,程序员","25","男",其中第一个字段包含逗号,因此用双引号包围;若字段是 "O'Neill",则应写成 """O""Neill"""

编码格式

常见的 CSV 文件编码有 UTF - 8、GBK 等。在读写 CSV 文件时,需要确保指定正确的编码格式,否则可能会出现乱码。例如,在使用 StreamReaderStreamWriter 时,可以通过 Encoding 参数指定编码:

using (StreamReader reader = new StreamReader("data.csv", System.Text.Encoding.UTF8))
{
    // 读取操作
}

二、读取 CSV 文件的多种方式

(一)使用StreamReader逐行读取

原理 :通过 StreamReader 逐行读取 CSV 文件内容,然后对每一行进行处理,将字符串按逗号分隔成数组。

代码示例

using System;
using System.Collections.Generic;
using System.IO;

class Program
{
    static void Main()
    {
        List<string[]> csvData = new List<string[]>();
        using (StreamReader reader = new StreamReader("data.csv"))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                // 将每一行按逗号分隔成数组
                string[] fields = line.Split(',');
                csvData.Add(fields);
            }
        }
        // 输出读取的数据
        foreach (string[] row in csvData)
        {
            foreach (string field in row)
            {
                Console.Write(field + "\t");
            }
            Console.WriteLine();
        }
    }
}
  • 优点 :简单易用,适合小型 CSV 文件的读取。
  • 缺点 :对于包含复杂字段(如字段中包含逗号、引号等特殊字符)的 CSV 文件,无法正确解析。

(二)使用TextFieldParser(需引用Microsoft.VisualBasic.dll组件)

  1. 原理TextFieldParser 是 .NET Framework 提供的一个专门用于解析文本文件的类,它可以更好地处理 CSV 文件中包含特殊字符的字段。
  2. 代码示例
using System;
using Microsoft.VisualBasic.FileIO;

class Program
{
    static void Main()
    {
        using (TextFieldParser parser = new TextFieldParser("data.csv"))
        {
            parser.TextFieldType = FieldType.Delimited;
            parser.SetDelimiters(",");
            while (!parser.EndOfData)
            {
                try
                {
                    string[] fields = parser.ReadFields();
                    foreach (string field in fields)
                    {
                        Console.Write(field + "\t");
                    }
                    Console.WriteLine();
                }
                catch (MalformedLineException ex)
                {
                    Console.WriteLine("行 {0} 格式错误: {1}", parser.LineNumber, ex.Message);
                }
            }
        }
    }
}
  1. 优点 :能够正确处理字段中包含逗号、引号等特殊字符的情况。
  2. 缺点 :需要引用 Microsoft.VisualBasic.dll 组件。

(三)使用第三方库(如 CsvHelper)

  • 原理 :CsvHelper 是一个功能强大的开源 CSV 操作库,它提供了更简便的 API,可以轻松地读取和写入 CSV 文件,并且支持将 CSV 数据映射到对象。
  • 安装 CsvHelper :通过 NuGet 包管理器安装 CsvHelper,命令如下:
Install-Package CsvHelper
  • 代码示例 - 读取 CSV 文件
using System;
using System.Collections.Generic;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;

class Program
{
    static void Main()
    {
        using (StreamReader reader = new StreamReader("data.csv"))
        using (CsvReader csv = new CsvReader(reader, new CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)))
        {
            var records = csv.GetRecords<Person>().ToList();
            foreach (Person person in records)
            {
                Console.WriteLine($"姓名: {person.Name}, 年龄: {person.Age}, 性别: {person.Gender}");
            }
        }
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}
  1. 优点 :功能强大,易于使用,支持对象映射和高级配置。
  2. 缺点 :需要引入外部依赖。

三、写入 CSV 文件的多种方式

(一)使用StreamWriter写入

  1. 原理 :将二维数据数组或列表转换为字符串,按行写入到 CSV 文件中。
  2. 代码示例
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string[][] data = new string[][]
        {
            new string[] {"姓名", "年龄", "性别"},
            new string[] {"张三", "25", "男"},
            new string[] {"李四", "30", "女"}
        };
        using (StreamWriter writer = new StreamWriter("data.csv"))
        {
            foreach (string[] row in data)
            {
                // 将数组元素用逗号连接成一行
                writer.WriteLine(string.Join(",", row));
            }
        }
    }
}
  • 优点 :简单易用,适合小型 CSV 文件的写入。
  • 缺点 :无法自动处理字段中的特殊字符。

(二)使用StringBuilder构建内容后写入

  1. 原理 :先用 StringBuilder 构建整个 CSV 内容,最后一次性写入文件,减少文件操作次数,尤其适用于大量数据写入。
  2. 代码示例
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        string[][] data = new string[][]
        {
            new string[] {"姓名", "年龄", "性别"},
            new string[] {"张三", "25", "男"},
            new string[] {"李四", "30", "女"}
        };
        StringBuilder sb = new StringBuilder();
        foreach (string[] row in data)
        {
            sb.AppendLine(string.Join(",", row));
        }
        File.WriteAllText("data.csv", sb.ToString());
    }
}
  1. 优点 :提高写入效率,适合大量数据写入。
  2. 缺点 :无法自动处理字段中的特殊字符。

(三)使用第三方库(如 CsvHelper)写入

  1. 原理 :利用 CsvHelper 提供的简便 API,将对象列表写入 CSV 文件,自动处理字段中的特殊字符。
  2. 代码示例
using System;
using System.Collections.Generic;
using System.IO;
using CsvHelper;

class Program
{
    static void Main()
    {
        List<Person> persons = new List<Person>
        {
            new Person { Name = "张三", Age = 25, Gender = "男" },
            new Person { Name = "李四", Age = 30, Gender = "女" }
        };
        using (StreamWriter writer = new StreamWriter("data.csv"))
        using (CsvWriter csv = new CsvWriter(writer, System.Globalization.CultureInfo.InvariantCulture))
        {
            csv.WriteRecords(persons);
        }
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}
  1. 优点 :功能强大,易于使用,自动处理特殊字符。
  2. 缺点 :需要引入外部依赖。

四、CSV 数据的解析与处理

(一)处理字段中的特殊字符

  1. 引号包围字段 :如果字段中包含逗号、引号或换行符,需要用双引号将字段包围起来。如果字段本身包含双引号,则需要用两个双引号表示一个双引号。
  2. 代码示例 - 写入包含特殊字符的字段
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string[][] data = new string[][]
        {
            new string[] {"姓名", "年龄", "爱好"},
            new string[] {"张三", "25", "读书, 旅行"},
            new string[] {"李四", "30", "打篮球\" \"排球"}
        };
        using (StreamWriter writer = new StreamWriter("data.csv"))
        {
            foreach (string[] row in data)
            {
                for (int i = 0; i < row.Length; i++)
                {
                    // 如果字段中包含逗号、引号或换行符,用双引号包围
                    if (row[i].Contains(",") || row[i].Contains("\"") || row[i].Contains("\n") || row[i].Contains("\r"))
                    {
                        // 将字段中的双引号替换为两个双引号
                        row[i] = "\"" + row[i].Replace("\"", "\"\"") + "\"";
                    }
                    writer.Write(row[i]);
                    if (i < row.Length - 1)
                    {
                        writer.Write(",");
                    }
                }
                writer.WriteLine();
            }
        }
    }
}

(二)将 CSV 数据映射到对象

  1. 定义数据类 :根据 CSV 文件的结构定义一个对应的类,方便对数据进行操作。
  2. 代码示例
using System;
using System.Collections.Generic;
using System.IO;

class Program
{
    static void Main()
    {
        List<Person> persons = new List<Person>();
        using (StreamReader reader = new StreamReader("data.csv"))
        {
            // 跳过标题行
            reader.ReadLine();
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                string[] fields = line.Split(',');
                Person person = new Person
                {
                    Name = fields[0],
                    Age = int.Parse(fields[1]),
                    Gender = fields[2]
                };
                persons.Add(person);
            }
        }
        // 输出对象数据
        foreach (Person person in persons)
        {
            Console.WriteLine($"姓名: {person.Name}, 年龄: {person.Age}, 性别: {person.Gender}");
        }
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

五、注意事项

文件路径问题    

  • 确保提供的文件路径正确。如果文件不存在,读取操作会抛出异常;如果写入路径无效,可能会导致写入失败或创建新文件在错误的位置。
  • 可以使用 File.Exists 方法检查文件是否存在:
if (!File.Exists("data.csv"))
{
    Console.WriteLine("文件不存在!");
}

数据类型转换问题 

  • 在将 CSV 数据转换为对象属性时,要注意数据类型的正确转换。如果转换失败,可能会引发异常,如将字符串转换为整数时,字符串不是有效的整数格式。
  • 可以使用 TryParse 方法进行安全转换:
int age;
if (int.TryParse(fields[1], out age))
{
    person.Age = age;
}
else
{
    Console.WriteLine("年龄数据格式错误!");
}

性能优化

  • 对于大型 CSV 文件的读写操作,可以考虑使用流式处理,避免一次性加载整个文件到内存中。例如,使用 StreamReader 逐行读取,或使用 StreamWriter 逐行写入。
  • 如果需要频繁读写 CSV 文件,可以考虑使用内存映射文件(Memory - Mapped Files)技术提高性能。

以上就是C#操作CSV文件的详细教程的详细内容,更多关于C#操作CSV文件的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈C#中正则表达式的使用

    浅谈C#中正则表达式的使用

    本篇文章主要介绍了C#中正则表达式的使用,具有一定的参考价值,有需要的可以了解一下。
    2016-12-12
  • C# SetWindowPos函数实例详解

    C# SetWindowPos函数实例详解

    在C#中,SetWindowPos函数用于设置窗口的位置和大小,这篇文章主要介绍了C# SetWindowPos函数实例详解,本文给大家介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • c# WinForm 窗体之间传值的几种方式(小结)

    c# WinForm 窗体之间传值的几种方式(小结)

    这篇文章主要介绍了WinForm 窗体之间传值的几种方式(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • C#中struct与class的区别详解

    C#中struct与class的区别详解

    本文主要介绍了C#中struct与class的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • c#中如何获取指定字符前的字符串

    c#中如何获取指定字符前的字符串

    这篇文章主要介绍了c#中如何获取指定字符前的字符串问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • C#中Decimal类型截取保留N位小数并且不进行四舍五入操作

    C#中Decimal类型截取保留N位小数并且不进行四舍五入操作

    这篇文章主要介绍了C#中Decimal类型截取保留N位小数并且不进行四舍五入操作,本文给出需求说明和实现代码,需要的朋友可以参考下
    2015-06-06
  • C# Winform TextBox控件多行输入方式

    C# Winform TextBox控件多行输入方式

    这篇文章主要介绍了C# Winform TextBox控件多行输入方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • C/C++ 传递动态内存的深入理解

    C/C++ 传递动态内存的深入理解

    本篇文章是对C/C++中的传递动态内存进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 在C#中生成PDF的步骤详解

    在C#中生成PDF的步骤详解

    在 .NET 世界中,存在许多 PDF 库,但我们发现,使用集成浏览器生成 PDF 更为简单,由于 DotNetBrowser 可以在完全脱离屏幕的情况下工作,本文给大家介绍了如何在 C# 中生成 PDF,需要的朋友可以参考下
    2024-10-10
  • 适用于WebForm Mvc的Pager分页组件C#实现

    适用于WebForm Mvc的Pager分页组件C#实现

    这篇文章主要为大家分享了适用于WebForm Mvc的Pager分页组件,由C#实现,感兴趣的小伙伴们可以参考一下
    2016-04-04

最新评论