C#中基于Hashtable实现两个CSV文件AccessDetails对比的问题
问题描述
现有两个CSV文件,均包含EmployeeId、Username等字段,其中AccessDetails字段格式为CardNumber|SecretPin|TokenNumber。需按以下规则对比处理:
- 卡号匹配但Token不匹配:不处理
- 卡号不匹配但Token匹配:不处理
AccessDetails为NULL时:将员工详情输出至其他文件- 卡号和Token均不匹配时:将员工详情输出至其他文件
当前采用Hashtable存储文件内容,以cardnumber为键,仅能实现第一条规则,无法处理卡号不同但Token相同的情况,也不知道如何处理AccessDetails为NULL的无关联记录。考虑将键设为cardnumber+tokennumber,但不知道如何在键中单独检索卡号或Token,寻求解决方案。
现有存储File1的代码:
if (!_File1.ContainsKey(cardnumber)) _File1.Add(cardnumber, username + "," + branchId + "," + employeeID + "," + cardnumber + "," + tokennumber + "," + empType + "," + newJoinee);
读取File2并对比的代码:
//readingFile2 data row = SplitCSV(line); employeeID = row[employeeIndex].Trim().ToString(); username = row[UsernameIndex].Trim().ToString(); branchID = row[branchIdIndex].Trim().ToString(); newJoinee = row[njIndex].Trim().ToString(); emptype = row[emptypeIdIndex].Trim().ToString(); accessdetails = row[ValueIndex].Trim().ToString(); if (!accessdetails.Equals("NULL")) { string[] values = value.Split('|'); cardnumberfile2 = values[0]; tokenumberFile2 = values[2]; } else { cardnumberfile2 = employeeID; tokennumberfile2 = ""; } if(_file1.ContainsKey(cardnumberfile2)) { //reading values from File1 // As cardnumber in file2 is present in the file1, then do nothing }
解决方案
1. 放弃Hashtable,改用强类型存储+双索引字典
用cardnumber+tokennumber当键没法单独检索卡号或Token,不如定义一个员工信息类,同时维护两个字典:
- 以
CardNumber为键,存储对应员工信息列表(兼容同卡号不同Token的场景) - 以
TokenNumber为键,存储对应员工信息列表
步骤1:定义员工信息类
public class EmployeeInfo { public string Username { get; set; } public string BranchId { get; set; } public string EmployeeId { get; set; } public string CardNumber { get; set; } public string TokenNumber { get; set; } public string EmpType { get; set; } public string NewJoinee { get; set; } // 快速转成CSV行的方法 public string ToCsvLine() { return $"{Username},{BranchId},{EmployeeId},{CardNumber},{TokenNumber},{EmpType},{NewJoinee}"; } }
步骤2:重构File1的存储逻辑
替换Hashtable为两个字典:
// 按卡号分组存储 Dictionary<string, List<EmployeeInfo>> _file1ByCard = new Dictionary<string, List<EmployeeInfo>>(); // 按Token分组存储 Dictionary<string, List<EmployeeInfo>> _file1ByToken = new Dictionary<string, List<EmployeeInfo>>(); // 存储File1数据时 EmployeeInfo empInfo = new EmployeeInfo { Username = username, BranchId = branchId, EmployeeId = employeeID, CardNumber = cardnumber, TokenNumber = tokennumber, EmpType = empType, NewJoinee = newJoinee }; // 添加到卡号字典 if (!_file1ByCard.ContainsKey(cardnumber)) { _file1ByCard[cardnumber] = new List<EmployeeInfo>(); } _file1ByCard[cardnumber].Add(empInfo); // 添加到Token字典(统一处理空Token场景) string tokenKey = string.IsNullOrEmpty(tokennumber) ? string.Empty : tokennumber; if (!_file1ByToken.ContainsKey(tokenKey)) { _file1ByToken[tokenKey] = new List<EmployeeInfo>(); } _file1ByToken[tokenKey].Add(empInfo);
2. 重构File2的对比处理逻辑
步骤1:优先处理AccessDetails为NULL的情况
直接写入目标文件,跳过后续对比:
if (accessdetails.Equals("NULL", StringComparison.OrdinalIgnoreCase)) { // 构造CSV行并写入文件 string outputLine = $"{username},{branchID},{employeeID},,,{emptype},{newJoinee}"; File.AppendAllText("NullAccessDetails.csv", outputLine + Environment.NewLine); continue; }
步骤2:解析AccessDetails并执行规则判断
string[] values = accessdetails.Split('|'); string cardFile2 = values[0].Trim(); string tokenFile2 = values[2].Trim(); // 检查是否存在匹配的卡号/Token bool hasMatchingCard = _file1ByCard.ContainsKey(cardFile2); bool hasMatchingToken = _file1ByToken.ContainsKey(tokenFile2); // 按规则分支处理 if (hasMatchingCard && !hasMatchingToken) { // 规则1:卡号匹配Token不匹配,不处理 continue; } else if (!hasMatchingCard && hasMatchingToken) { // 规则2:卡号不匹配Token匹配,不处理 continue; } else if (!hasMatchingCard && !hasMatchingToken) { // 规则4:卡号和Token都不匹配,写入目标文件 string outputLine = $"{username},{branchID},{employeeID},{cardFile2},{tokenFile2},{emptype},{newJoinee}"; File.AppendAllText("MismatchedRecords.csv", outputLine + Environment.NewLine); } // 剩余场景:卡号和Token都匹配,不处理
3. 额外注意事项
- 字符串比较用
StringComparison.OrdinalIgnoreCase避免大小写问题 - 空Token统一用空字符串作为键,避免索引混乱
- 数据量大时建议用
StreamWriter批量写入文件,比File.AppendAllText性能更优
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

