C#将JSON对象写入文件 C#如何优雅地将一个C#对象序列化为JSON文件

8次阅读

system.text.json流式写入json文件最轻量,.net core 3.0+原生支持;应使用serializeasync配合FileStream避免内存峰值,指定writeindented=true便于调试,注意datetime默认iso格式及streamwriter提前释放问题。

C#将JSON对象写入文件 C#如何优雅地将一个C#对象序列化为JSON文件

System.Text.Json 直接写入文件最轻量

不需要额外 NuGet 包,.NET Core 3.0+ 和 .NET 5+ 原生支持。关键不是“先序列化成字符串再写”,而是用 JsonSerializer.SerializeAsync 配合 FileStream 流式写入,避免大对象引发的内存峰值。

实操建议:

  • 始终指定 new JsonSerializerOptions { WriteIndented = true },方便调试和人工查看
  • 若对象含 DateTime,注意默认序列化格式是 ISO 8601(如 "2024-05-20T09:30:00Z"),无需额外配置
  • 遇到 NotSupportedException: Cannot write to a closed TextWriter,大概率是 StreamWriter 被提前 dispose,应确保 FileStream 和序列化共用同一作用域
var options = new JsonSerializerOptions { WriteIndented = true }; await using var stream = File.Create("data.json"); await JsonSerializer.SerializeAsync(stream, myObj, options);

处理 Newtonsoft.Json(Json.NET)的兼容写法

老项目还在用 Newtonsoft.Json?它不支持直接流式序列化到文件,但可以避免中间字符串分配:用 JsonTextWriter 包装 FileStream

常见错误现象:

  • JsonConvert.SerializeObject(obj)File.WriteAllText → 大对象时 GC 压力陡增
  • 忘记设置 textWriter.CloseOutput = false → 文件末尾多出一个空字节或截断
  • DateTime 默认输出为 /Date(1716203400000)/ 格式 → 应显式设 dateFormatHandling: DateFormatHandling.IsoDateFormat
using var stream = File.Create("data.json"); using var writer = new StreamWriter(stream); using var jsonWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }; var serializer = new JsonSerializer { DateFormatHandling = DateFormatHandling.IsoDateFormat }; serializer.Serialize(jsonWriter, myObj);

需要控制字段忽略或重命名?别硬编码 [JsonIgnore]

运行时动态决定哪些属性写入 JSON,比加一特性更灵活。比如导出时隐藏敏感字段、或按角色过滤字段。

实操要点:

  • System.Text.Json 用自定义 JsonConverter<t></t>继承 JsonSerializerContext 配置 JsonSerializerOptions
  • Newtonsoft.Json 更直接:用 ContractResolver 子类,在 CreateProperty 中判断 memberInfo.Name 并设 shouldSerialize = false
  • 别在序列化前手动克隆对象删字段——破坏原始状态,且无法处理嵌套引用

异步写入失败却没报错?检查 FileStreamFileShare

常见静默失败场景:多个线程/进程同时尝试写同一个 JSON 文件,File.Create 默认以 FileShare.None 打开,后继写入会卡住或抛 IOException 但被吞掉。

必须明确:

  • 写文件时不要用 File.OpenWrite,它不支持异步;坚持用 File.CreateFileStream 构造函数
  • 如果需并发写不同文件,确保路径唯一;若真要覆盖同一文件,加 lock 或用 SemaphoreSlim 控制写入节奏
  • 捕获 IOException 后检查 ex.HResult == -2147024864(即 ERROR_SHARING_VIOLATION),这是 windows 下共享冲突的典型信号

写 JSON 文件真正的复杂点不在序列化本身,而在路径权限、并发控制、以及序列化器对循环引用或不可序列化类型的默认行为——这些往往在测试环境不暴露,上线后才突然触发。

text=ZqhQzanResources