跳转到内容

C Sharp CSV 文件处理

来自代码酷

C# CSV文件处理[编辑 | 编辑源代码]

CSV(Comma-Separated Values)是一种简单的文件格式,用于存储表格数据(如电子表格或数据库)。在C#中处理CSV文件是常见的任务,特别是在数据导入/导出、报表生成等场景中。

CSV格式简介[编辑 | 编辑源代码]

CSV文件由以下特点组成:

  • 每行代表一条记录
  • 记录由分隔符(通常是逗号)分隔的字段组成
  • 第一行通常是标题行(可选)
  • 字段值可以包含在引号中(特别是当值本身包含分隔符时)

示例CSV文件内容:

Name,Age,Email
"John Doe",30,john@example.com
"Jane Smith",25,jane@example.com

C#中的基本CSV处理[编辑 | 编辑源代码]

使用字符串分割[编辑 | 编辑源代码]

对于简单的CSV文件,可以使用字符串分割方法:

using System;
using System.IO;

class CSVReader
{
    static void Main()
    {
        string filePath = "data.csv";
        
        try
        {
            string[] lines = File.ReadAllLines(filePath);
            
            // 假设第一行是标题
            string[] headers = lines[0].Split(',');
            
            for (int i = 1; i < lines.Length; i++)
            {
                string[] fields = lines[i].Split(',');
                
                Console.WriteLine($"Record {i}:");
                for (int j = 0; j < fields.Length; j++)
                {
                    Console.WriteLine($"  {headers[j]}: {fields[j]}");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error reading CSV: {ex.Message}");
        }
    }
}

输出示例:

Record 1:
  Name: "John Doe"
  Age: 30
  Email: john@example.com
Record 2:
  Name: "Jane Smith"
  Age: 25
  Email: jane@example.com

处理带引号的字段[编辑 | 编辑源代码]

当字段包含分隔符时,简单的Split方法会失效。可以使用正则表达式或更复杂的解析逻辑:

using System.Text.RegularExpressions;

// 改进的分割方法,处理带引号的字段
string[] SplitCSVLine(string line)
{
    var pattern = ",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))";
    return Regex.Split(line, pattern);
}

使用专用库处理CSV[编辑 | 编辑源代码]

对于更复杂的CSV处理,推荐使用专用库如CsvHelper。

安装CsvHelper[编辑 | 编辑源代码]

通过NuGet包管理器安装:

Install-Package CsvHelper

基本用法示例[编辑 | 编辑源代码]

using CsvHelper;
using System.Globalization;
using System.IO;
using System.Linq;

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

class Program
{
    static void Main()
    {
        // 读取CSV
        using (var reader = new StreamReader("data.csv"))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            var records = csv.GetRecords<Person>().ToList();
            
            foreach (var person in records)
            {
                Console.WriteLine($"Name: {person.Name}, Age: {person.Age}, Email: {person.Email}");
            }
        }
        
        // 写入CSV
        var people = new List<Person>
        {
            new Person { Name = "John Doe", Age = 30, Email = "john@example.com" },
            new Person { Name = "Jane Smith", Age = 25, Email = "jane@example.com" }
        };
        
        using (var writer = new StreamWriter("output.csv"))
        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            csv.WriteRecords(people);
        }
    }
}

高级主题[编辑 | 编辑源代码]

处理大型CSV文件[编辑 | 编辑源代码]

对于大型CSV文件,应使用流式处理而非一次性加载全部内容:

using (var reader = new StreamReader("largefile.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Read();
    csv.ReadHeader();
    
    while (csv.Read())
    {
        var record = csv.GetRecord<Person>();
        // 处理每条记录
    }
}

自定义映射[编辑 | 编辑源代码]

当CSV列名与类属性名不匹配时,可以使用自定义映射:

public sealed class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {
        Map(m => m.Name).Name("FullName");
        Map(m => m.Age).Name("Years");
        Map(m => m.Email).Name("EmailAddress");
    }
}

// 使用前注册映射
csv.Context.RegisterClassMap<PersonMap>();

实际应用案例[编辑 | 编辑源代码]

案例1:导入用户数据[编辑 | 编辑源代码]

假设需要从CSV导入用户数据到数据库:

public void ImportUsersFromCSV(string filePath)
{
    using (var reader = new StreamReader(filePath))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        var users = csv.GetRecords<User>().ToList();
        
        using (var dbContext = new AppDbContext())
        {
            dbContext.Users.AddRange(users);
            dbContext.SaveChanges();
        }
    }
}

案例2:生成报表[编辑 | 编辑源代码]

从数据库查询数据并导出为CSV报表:

public void ExportReportToCSV(string filePath)
{
    using (var dbContext = new AppDbContext())
    {
        var reportData = dbContext.Sales
            .Where(s => s.Date.Year == DateTime.Now.Year)
            .OrderBy(s => s.Date)
            .ToList();
            
        using (var writer = new StreamWriter(filePath))
        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            csv.WriteRecords(reportData);
        }
    }
}

性能考虑[编辑 | 编辑源代码]

处理CSV文件时应注意以下性能因素:

  • 对于大文件,使用流式处理而非一次性加载
  • 考虑使用并行处理(当记录间无依赖时)
  • 适当使用缓冲(BufferSize)
  • 避免不必要的类型转换

常见问题与解决方案[编辑 | 编辑源代码]

问题 解决方案
字段包含分隔符 确保字段用引号括起来,使用正确的解析方法
多行字段 使用支持多行字段的解析库
编码问题 明确指定文件编码(如UTF-8)
性能问题 使用流式处理,考虑内存映射文件
日期格式不一致 在读取时指定文化信息或自定义转换器

总结[编辑 | 编辑源代码]

C#提供了多种处理CSV文件的方法,从简单的字符串分割到使用功能丰富的第三方库。选择哪种方法取决于具体需求:

  • 对于简单、格式规范的CSV,内置方法可能足够
  • 对于复杂或生产环境的需求,推荐使用CsvHelper等专业库
  • 处理大型文件时,务必考虑内存使用和性能优化

掌握CSV文件处理是C#开发中的实用技能,适用于各种数据交换和报表生成场景。