CSV 文件读取:用 File.ReadAllLines
最快但不安全
直接用
File.ReadAllLines读 CSV 看似简单,实际会崩在带换行符的字段(比如 Excel 导出的备注列里有回车)、中文乱码、逗号嵌套等场景。它只是按行切,完全不管 CSV 的 RFC 4180 规则。
实操建议:
优先用Microsoft.Data.SqlClient不合适——那是 SQL Server;这里该用
System.Data.Common+
Microsoft.Data.DataView?不对,太重。轻量级选
Microsoft.VisualBasic.FileIO.TextFieldParser(别被命名劝退,C# 项目可直接引用
Microsoft.VisualBasicNuGet 包,稳定且处理引号/换行/空字段都正确) 如果必须手写解析,至少用
StreamReader配合状态机,而不是
Split(',')) —— 后者在 "a,b",c,"d,e,f"这种数据上直接错三列 编码问题高频:Windows 记事本存的 CSV 默认是
GBK或
UTF-8 with BOM,
File.ReadAllLines默认用
UTF-8,BOM 会被当内容;显式传
Encoding.UTF8或
Encoding.Default更可控
JSON 文件查询:别用 JsonConvert.DeserializeObject
全量加载大文件
把几 MB 的 JSON 当“数据库”查,一上来就
JsonConvert.DeserializeObject<list>>(json)</list>,内存暴涨、GC 频繁,查一次卡两秒。这不是反模式,是典型误用。
实操建议:
小文件(System.Text.Json 的JsonSerializer.Deserialize<t></t>没问题,类型安全又快 中大文件(>1MB)或只查部分字段:改用
JsonDocument.Parse+
RootElement导航,它只解析 JSON 结构树,不 new 对象,内存占用低 60% 以上 想支持类似 SQL 的查询语法?别自己写解析器。用
System.Linq.Dynamic.Core库配合
JsonElement转
IEnumerable<object></object>,能写
Where("Price > 100") 这种字符串条件,但注意:字段名大小写要和 JSON 一致,price≠
Price
文件即数据库的边界在哪:什么时候该换 SQLite
CSV/JSON 当数据库,本质是把磁盘 I/O 当查询引擎用。查一次开一次文件、全扫描、没索引、没事务——这些不是“功能缺失”,是设计定位决定的。
实操判断点:
单次查询响应超过 200ms(比如 10 万行 CSV 里Where查某 ID)→ 该上
SQLite需要多表关联、分页(
OFFSET/LIMIT)、模糊匹配(
LIKE '%abc%')→ CSV/JSON 基本不可行 并发写入:两个进程同时
File.WriteAllText写同一个 JSON,大概率文件损坏;而
SQLite的 WAL 模式天然支持多线程写 迁移成本极低:NuGet 装
Microsoft.Data.Sqlite,把原 CSV 用
DbCommand批量 INSERT 进
.db文件,后续代码只需改连接字符串和 SQL,业务逻辑几乎不动
查询性能陷阱:LINQ to Objects 不是 LINQ to SQL
很多人把
List<t></t>从文件加载后,写
data.Where(x => x.Name.Contains("abc")) 就以为是“高效查询”。其实这是纯内存遍历,复杂度 O(n),且每次调用都重新扫描。
关键差异:
Where在内存集合上执行,无法跳过无关行;而 SQLite 的
WHERE name LIKE ?可走索引(如果建了) JSON 中用
JsonElement.GetProperty("name").GetString() 做比较前,先确认字段存在(TryGetProperty),否则抛
KeyNotFoundException,不是所有 JSON 行都有
nameCSV 场景下,如果反复查同一列,别每次都
line.Split(',')[2] —— 先用 TextFieldParser解析成对象列表,再用 LINQ,否则拆分开销比查询本身还高
文件当数据库,最易被忽略的是“查询意图”和“物理存储”的错配:你想要索引、缓存、并发控制,但文件系统只提供字节流。这点不认清,优化永远在边缘打转。
