如何使用CsvHelper读取CSV首行与末行并验证日期范围
用CsvHelper读取CSV首行与末行(无需全量加载)
要验证CSV的日期范围,不用把整个文件加载到内存,分两步处理首行和末行:
读取首行
首行读取逻辑很简单,直接用CsvHelper的常规读取流程即可:
using (var reader = new StreamReader("target.csv")) using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) { // 读取表头(如果CSV包含表头) csv.Read(); csv.ReadHeader(); // 读取第一行数据 csv.Read(); var firstRow = csv.GetRecord<YourDataModel>(); // 替换成你的实体类 DateTime firstDate = firstRow.RecordDate; // 替换为你的日期字段名 }
读取末行
大文件直接读末行不能靠全量遍历,得通过文件流从尾部反向定位换行符,找到末行起始位置后再读取解析:
string lastLine = null; var buffer = new byte[1024]; var lineBreakBytes = Encoding.UTF8.GetBytes(Environment.NewLine); using (var fileStream = new FileStream("target.csv", FileMode.Open, FileAccess.Read, FileShare.Read)) { long currentPosition = fileStream.Length; while (currentPosition > 0) { var bytesToRead = Math.Min(buffer.Length, currentPosition); currentPosition -= bytesToRead; fileStream.Seek(currentPosition, SeekOrigin.Begin); fileStream.Read(buffer, 0, (int)bytesToRead); // 反向扫描缓冲区找换行符 for (int i = (int)bytesToRead - 1; i >= 0; i--) { bool isLineBreak = false; // 兼容Windows(\r\n)和Unix(\n)换行 if (buffer[i] == lineBreakBytes[^1]) { if (lineBreakBytes.Length == 2 && i > 0 && buffer[i-1] == lineBreakBytes[0]) { isLineBreak = true; currentPosition += i + 2; // 跳过换行符本身 } else if (lineBreakBytes.Length == 1) { isLineBreak = true; currentPosition += i + 1; } } if (isLineBreak) { // 读取末行内容 var remainingLength = (int)(fileStream.Length - currentPosition); var lastLineBytes = new byte[remainingLength]; fileStream.Seek(currentPosition, SeekOrigin.Begin); fileStream.Read(lastLineBytes, 0, remainingLength); lastLine = Encoding.UTF8.GetString(lastLineBytes).Trim(); goto EndSearch; } } } // 处理文件只有一行的情况 if (lastLine == null) { fileStream.Seek(0, SeekOrigin.Begin); using (var streamReader = new StreamReader(fileStream)) { lastLine = streamReader.ReadToEnd().Trim(); } } EndSearch: // 用CsvHelper解析末行 using (var stringReader = new StringReader(lastLine)) using (var csv = new CsvReader(stringReader, CultureInfo.InvariantCulture)) { // 因为只传入单行数据,需关闭表头检测 csv.Configuration.HasHeaderRecord = false; var lastRow = csv.GetRecord<YourDataModel>(); DateTime lastDate = lastRow.RecordDate; } }
关键注意点
- 替换
YourDataModel为你自己的实体类,确保属性和CSV列对应,可通过[Name("列名")]特性做列名映射 - 如果CSV用了非UTF8编码(比如GBK),要替换代码中的
Encoding.UTF8为对应编码 - 若CSV末尾可能存在空行,需在获取
lastLine后判断是否为空,若为空则继续向前查找有效行
内容的提问来源于stack exchange,提问作者katanisk8
相关产品推荐
相关产品推荐

