C# WPF程序CSV导入数据库时最后两条数据丢失如何修复
C# CSV导入丢失最后2条数据修复方案
问题现象
读取CSV存入数据库时,最后2条条目未进入persons集合,集合末尾索引值为空。

核心错误点
- 所有循环边界错误减去2:代码中
linesinthestream.Count()-2、x[0].Count-2、x.Count-2这类写法直接跳过了最后2个元素,是丢失数据的直接原因 - 换行符处理缺失:Windows系统CSV文件换行是
\r\n,仅按\n分割会导致每行末尾残留\r,容易产生空值、空行 - 空列逻辑错误:遇到空表头列直接执行
return会直接终止整个导入流程,只要CSV存在空列就会中断 - 冗余文件读取:同一个文件连续打开读取两次,既影响性能,也可能出现文件占用、内容不一致问题
- 固定长度初始化逻辑不合理:提前按估算长度初始化
persons集合,一旦长度计算错误就会出现索引越界、数据缺失 - 表头被误判为数据:代码把表头行也存入了
persons集合,只能后续靠RemoveAt(0)删除,逻辑冗余易错
修复后可直接运行的代码
private void Import_CSV_Click(object sender, System.Windows.RoutedEventArgs e) { List<List<string>> csvData = new List<List<string>>(); try { OpenFileDialog browseDialog = new OpenFileDialog(); browseDialog.Filter = "CSV Files (*.csv)|*.csv"; if (browseDialog.ShowDialog() != true) return; // 用户取消选择文件直接返回 // 一次性读取文件,自动释放流资源 string fileContent; using (StreamReader sr = new StreamReader(browseDialog.FileName, Encoding.Default, true)) { fileContent = sr.ReadToEnd(); } // 分割行,处理\r\n换行符,过滤空行 var lines = fileContent.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(line => line.TrimEnd('\r')) .ToList(); if (lines.Count == 0) { MessageBox.Show("CSV文件为空"); return; } // 解析表头 string[] headers = Akro.Helpers.String.RemoveDiacritics(lines[0].ToLower()).Split(';'); csvData.Add(headers.ToList()); // 解析所有数据行 for (int i = 1; i < lines.Count; i++) { string[] rowValues = lines[i].Split(';'); csvData.Add(rowValues.ToList()); } List<TOsoby> persons = new List<TOsoby>(); // 遍历所有表头列做字段映射 for (int colIndex = 0; colIndex < csvData[0].Count; colIndex++) { string currentHeader = csvData[0][colIndex].Trim(); // 遍历所有数据行,跳过表头 for (int rowIndex = 1; rowIndex < csvData.Count; rowIndex++) { // 对应人员对象不存在则新增 if (persons.Count < rowIndex) { persons.Add(new TOsoby { OsobaID = 0 }); } string cellValue = csvData[rowIndex][colIndex]; // 多语言表头字段匹配 switch (currentHeader) { case "jmeno": case "name": case "firstname": persons[rowIndex - 1].Jmeno = cellValue; break; case "prijmeni": case "surname": case "lastname": case "familyname": persons[rowIndex - 1].Prijmeni = cellValue; break; case "titul": case "title": persons[rowIndex - 1].Titul = cellValue; break; case "email": persons[rowIndex - 1].Email = cellValue; break; case "": // 空列直接跳过,不终止整个导入流程 continue; } } } if (persons.Count == 0) { MessageBox.Show("未解析到有效人员数据"); return; } EntitiesModel em = DB.GetDB(); em.Add(persons); em.SaveChanges(); Checker.CheckAfterEverySave(); MessageBox.Show($"成功导入{persons.Count}条人员数据"); } catch (Exception er) { MessageBox.Show($"导入失败:{er.Message}"); } }
关键修改说明
- 删除了所有循环边界无意义的
-2写法,按集合实际长度遍历,不会再跳过最后2条数据 - 新增换行符处理逻辑,统一清除Windows换行符残留的
\r,避免出现尾部空值 - 把空表头的
return逻辑改为continue,空列只会跳过当前字段映射,不会终止整个导入 - 去掉重复读取文件的逻辑,用
using包裹流读取,自动释放资源,避免文件占用 - 改为动态新增
persons集合元素,不需要提前计算长度,从根源避免长度计算错误导致的索引问题 - 遍历数据时直接跳过表头行,不需要后续再调用
RemoveAt(0)删除无效数据 - 新增用户取消选文件、空文件、无有效数据的判断,避免空引用报错
内容的提问来源于stack exchange,提问作者Matthewis
相关产品推荐
相关产品推荐

