C#读取文件夹txt/csv/xml文件导入SQL数据库并避免重复导入的方案
最优实现方案
核心逻辑设计思路
- 双保险去重机制:从文件层面避免重复处理、从数据库层面避免冗余数据
- 格式适配解析:针对三类文件分别使用对应解析逻辑,统一映射到CustomerModel
- 启动单次触发:在应用启动入口嵌入执行逻辑,全程仅执行一次
1. 去重机制实现
1.1 新增文件导入记录表
首先在数据库新增FileImportRecords表,对应模型如下:
public class FileImportRecord { public int Id { get; set; } // 文件名+最后修改时间的哈希值,唯一标识文件版本 public string FileUniqueHash { get; set; } public DateTime ImportTime { get; set; } }
每次读取文件前,先计算文件的唯一哈希(可组合文件名、文件大小、最后修改时间计算MD5值),如果哈希值已存在于导入记录表,直接跳过该文件。
1.2 数据库唯一约束
给Customer表添加业务唯一键约束,就算异常触发重复处理也不会生成冗余数据:
ALTER TABLE Customers ADD CONSTRAINT UC_Customer_BizKey UNIQUE (CustomerNumber, ProductNumber, Name, Quantity);
可根据实际业务规则调整唯一键的字段组合
2. 多格式文件解析与导入逻辑
可引入第三方库简化解析:CSV/TXT用CsvHelper,XML用系统自带的System.Xml.Linq
// 核心导入方法示例 public async Task ImportFilesAsync() { var targetDir = Path.Combine(AppContext.BaseDirectory, "my-folder"); var allowedExtensions = new[] { ".txt", ".csv", ".xml" }; var files = Directory.EnumerateFiles(targetDir, "*.*", SearchOption.TopDirectoryOnly) .Where(f => allowedExtensions.Contains(Path.GetExtension(f).ToLower())) .ToList(); foreach (var file in files) { // 计算文件唯一哈希 var fileInfo = new FileInfo(file); var hashSource = $"{fileInfo.Name}_{fileInfo.Length}_{fileInfo.LastWriteTimeUtc.Ticks}"; var fileHash = Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(hashSource))); // 检查是否已导入 if (await _dbContext.FileImportRecords.AnyAsync(r => r.FileUniqueHash == fileHash)) continue; // 解析文件 List<CustomerModel> customers = Path.GetExtension(file).ToLower() switch { ".txt" or ".csv" => ParseCsvOrTxt(file), ".xml" => ParseXml(file), _ => new List<CustomerModel>() }; // 批量插入数据库 if (customers.Any()) { await _dbContext.Customers.AddRangeAsync(customers); // 标记文件已导入 await _dbContext.FileImportRecords.AddAsync(new FileImportRecord { FileUniqueHash = fileHash, ImportTime = DateTime.UtcNow }); await _dbContext.SaveChangesAsync(); } } } // CSV/TXT解析示例(基于CsvHelper) private List<CustomerModel> ParseCsvOrTxt(string filePath) { using var reader = new StreamReader(filePath); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); return csv.GetRecords<CustomerModel>().ToList(); } // XML解析示例 private List<CustomerModel> ParseXml(string filePath) { var doc = XDocument.Load(filePath); return doc.Descendants("Customer") .Select(x => new CustomerModel { CustomerNumber = (int)x.Element("CustomerNumber"), ProductNumber = (string)x.Element("ProductNumber"), Quantity = (int)x.Element("Quantity"), Name = (string)x.Element("Name") }).ToList(); }
3. 启动时单次执行配置
- 若为ASP.NET Core项目:在
Program.cs中构建完WebApp后,运行启动逻辑再启动服务:
var app = builder.Build(); // 执行导入 using (var scope = app.Services.CreateScope()) { var importService = scope.ServiceProvider.GetRequiredService<IImportService>(); await importService.ImportFilesAsync(); } app.Run();
- 若为控制台项目:直接在
Main方法入口处调用导入方法即可。
内容的提问来源于stack exchange,提问作者DavidHansson
相关产品推荐
相关产品推荐

