You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中正确读取CSV文件中的捷克语特殊字符?

解决C# WPF导入含捷克语特殊字符的分号分隔CSV问题

问题背景

我开发的C# WPF应用需要导入分号分隔的CSV文件,文件包含多列(部分列可能为空),其中第一、二列是带捷克语特殊字符(如ščřěžýáíé或ŠČŘĚŽÝÁÍÉ)的姓名,必须正确解析这些姓名。

CSV文件示例:

"name";"surname"
"Adam";"Veselý"
"David";"Řehořčík"

使用CsvHelper库时,特殊字符被替换为�,设置Encoding.UTF8无效。已安装System.Text.Encoding.CodePages NuGet包,但系统无法识别Windows-1250、Windows-1252编码,问题仍未解决。

以下是当前使用的导入函数:

public void ImportStudentsFromCsv(object obj)
{
    // Open file dialog to select CSV file
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = "CSV files (*.csv)|*.csv";
    openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    openFileDialog.Title = "Select CSV file";

    if (openFileDialog.ShowDialog() == true)
    {
        string filePath = openFileDialog.FileName;

        try
        {
            // Configure CsvHelper to handle semicolon delimiter and diacritics
            var csvConfig = new CsvConfiguration(CultureInfo.InvariantCulture)
            {
                Delimiter = ";",
                HasHeaderRecord = true, // Assume CSV has header
                Encoding = Encoding.UTF8,
                BadDataFound = null // Ignore bad data
            };

            using (var reader = new StreamReader(filePath, Encoding.UTF8))
            using (var csv = new CsvReader(reader, csvConfig))
            {
                // Read CSV records into Student objects
                var records = csv.GetRecords<dynamic>();

                // Initialize the students list
                _students = new List<Student>();

                foreach (var record in records)
                {
                    // Map CSV values to Student properties
                    var student = new Student
                    {
                        StudentName = record.jmeno,
                        StudentSurname = record.prijmeni,
                        StudentProgram = record.oborKomb,
                        StudentYear = Convert.ToInt32(record.rocnik),
                        ClassId = SelectedClass.Id,
                        Card = "card not assigned"
                    };

                    // Add student to the list
                    _students.Add(student);
                }
            }

            // Save students to the database
            using (var db = new UserContext())
            {
                db.student.AddRange(_students);
                db.SaveChanges();
            }

            // Update the UI
            OnPropertyChanged(nameof(Students));
        }
        catch (Exception ex)
        {
            MessageBox.Show($"Error occurred while importing students: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }
}

解决方案

1. 注册代码页编码

安装System.Text.Encoding.CodePages后,必须在应用启动时注册编码提供器,否则系统无法识别Windows-1250这类非内置编码。在App.xaml.cs的OnStartup方法或程序入口中添加:

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

2. 检测CSV文件的实际编码

UTF8不一定是文件的真实编码,捷克语CSV常用Windows-1250编码。可以用以下方法检测文件编码:

public static Encoding DetectFileEncoding(string filePath)
{
    using (var reader = new StreamReader(filePath, Encoding.Default, true))
    {
        reader.Peek(); // 触发编码检测
        return reader.CurrentEncoding;
    }
}

3. 修正CsvHelper配置与读取逻辑

  • 移除CsvConfig中的Encoding设置,让StreamReader的编码主导解析过程
  • 改用强类型映射替代dynamic,避免属性名匹配错误(示例中CSV表头为name/surname,但代码中用record.jmeno/prijmeni,存在明显不匹配)

修正后的核心代码:

// 检测文件实际编码
var fileEncoding = DetectFileEncoding(filePath);

var csvConfig = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    Delimiter = ";",
    HasHeaderRecord = true,
    BadDataFound = null
};

using (var reader = new StreamReader(filePath, fileEncoding))
using (var csv = new CsvReader(reader, csvConfig))
{
    // 注册强类型映射规则
    csv.Context.RegisterClassMap<StudentCsvMap>();
    // 读取为强类型模型
    var csvRecords = csv.GetRecords<StudentCsvModel>();
    
    _students = csvRecords.Select(record => new Student
    {
        StudentName = record.Name,
        StudentSurname = record.Surname,
        StudentProgram = record.OborKomb,
        StudentYear = record.Rocnik,
        ClassId = SelectedClass.Id,
        Card = "card not assigned"
    }).ToList();
}

// 定义CSV对应的模型类
public class StudentCsvModel
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public string OborKomb { get; set; }
    public int Rocnik { get; set; }
}

// 定义CsvHelper映射规则
public class StudentCsvMap : ClassMap<StudentCsvModel>
{
    public StudentCsvMap()
    {
        Map(m => m.Name).Name("name"); // 对应CSV表头的name列
        Map(m => m.Surname).Name("surname"); // 对应CSV表头的surname列
        Map(m => m.OborKomb).Name("oborKomb");
        Map(m => m.Rocnik).Name("rocnik");
    }
}

4. 验证编码与数据

  • 用Notepad++打开CSV文件,查看菜单「编码」下的当前编码,确认检测结果是否正确
  • 读取数据后通过调试或日志输出,验证捷克语特殊字符是否正常显示

内容的提问来源于stack exchange,提问作者yanni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 07:36:03