C#/Core MVC上传解析CSV文件时遇文件为空及流超时异常问题
问题根因
1. 行计数逻辑错误
行计数变量count被定义在while循环内部,每次循环迭代都会被重置为0,导致if (count++ == 0) continue判断每次都命中,所有行都被直接跳过,表现为读取不到任何内容,误认为文件为空。
2. 文件流未释放就发起读取
写入文件用的FileStream处于using作用域内时,文件句柄被独占,部分写入内容可能还在系统缓冲区未刷入磁盘,此时直接通过路径读取文件会触发读取异常或拿到空内容。
3. 超时异常属于正常现象
调试时看到的stream.ReadTimeout/stream.WriteTimeout抛出System.InvalidOperationException是正常表现:IFormFile对应的HTTP请求流默认不支持超时配置,访问这两个属性就会触发异常,该异常不会影响正常的流读写操作,无需额外处理。
修复方案
方案1:本地存储后读取
将行计数变量移到循环外,写完文件后先释放写入流再读取:
private Dictionary<string, string[]> LoadData(IFormFile file) { // 校验文件有效性 if (file != null && file.Length > 0) { string wwwPath = this.environment.WebRootPath; string path = Path.Combine(wwwPath, "WeeklySchedules"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string fileName = Path.GetFileName(file.FileName); string fullPath = Path.Combine(path, fileName); // 先完成写入,释放文件流 using (FileStream stream = new FileStream(fullPath, FileMode.Create)) { file.CopyTo(stream); } // 单独开启读取流解析 using (TextFieldParser parser = new TextFieldParser(fullPath)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); Dictionary<string, string[]> parsedData = new Dictionary<string, string[]>(); // 计数变量移到循环外 int count = 0; while (!parser.EndOfData) { string[] fields = parser.ReadFields(); // 跳过表头行 if (count++ == 0) { continue; } var pickup = fields[0]; var pickupDate = fields[1]; var dropoff = fields[2]; var dropoffDate = fields[3]; var driver = fields[7]; var pickupTime = DateTime.Parse(pickupDate).ToLongTimeString(); // 此处补充业务逻辑,往parsedData中插入数据 } return parsedData; } } return null; }
方案2:直接读取上传流(无需本地存储)
跳过本地存盘步骤,直接读取IFormFile的流解析,性能更优:
private Dictionary<string, string[]> LoadData(IFormFile file) { if (file != null && file.Length > 0) { using (var stream = file.OpenReadStream()) using (TextFieldParser parser = new TextFieldParser(stream)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); Dictionary<string, string[]> parsedData = new Dictionary<string, string[]>(); int count = 0; while (!parser.EndOfData) { string[] fields = parser.ReadFields(); if (count++ == 0) { continue; } var pickup = fields[0]; var pickupDate = fields[1]; var dropoff = fields[2]; var dropoffDate = fields[3]; var driver = fields[7]; var pickupTime = DateTime.Parse(pickupDate).ToLongTimeString(); // 补充业务逻辑 } return parsedData; } } return null; }
内容的提问来源于stack exchange,提问作者Gregory Hill
相关产品推荐
相关产品推荐

