You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# DataTable调用WriteXml方法保存文件无内容变更问题排查

问题核心原因

  • 线程安全缺失:旧代码有lock(users)保护DataTable并发读写,改造后的异步代码直接移除了锁。DataTable不支持多线程并发修改,若有其他线程同时读写users实例,会出现更新丢失、遍历异常、数据不一致问题,直接导致写入XML的内容不是最新值。
  • 异步写法错误:
    1. 根方法用async void,方法内抛出的异常无法被外层捕获,直接导致进程终止或逻辑中断,且你没有对应日志可以感知到报错。
    2. async方法内用Thread.Sleep会阻塞当前线程,完全浪费异步特性,应该替换为await Task.Delay。
    3. 手动创建Task实例再调用Start属于多余操作,你的更新、写入逻辑都是CPU+IO混合的同步逻辑,直接串行执行即可,额外创建线程只会增加调度开销,还可能引发并发问题。
  • 时间戳取值错误:时间戳固定相差10秒,大概率是TimeCurrent变量不是每次执行UvalClockTaksAsync时实时获取的,而是提前缓存的旧值,或者TimeCurrent的更新频率是10秒一次,和你的30秒保存逻辑存在时间差。
  • DataTable更改未提交:修改DataRow的值后如果没有调用AcceptChanges,WriteXml默认可能读取行的原始版本而非修改后的版本,导致写入的内容和之前完全一致,这也符合你遇到的Notepad++提示文件修改但内容无变化的现象(文件修改时间更新,但内容哈希和旧文件完全相同)。
  • 替换逻辑无校验:File.Replace操作如果遇到目标文件被占用、权限不足等问题会抛出异常,你虽然加了catch,但如果日志写入成功你没有主动查看log.txt的内容,根本感知不到替换失败的问题,这就是users.xml和users.xml_be内容不一致的核心原因:替换操作失败了,临时文件是最新的,但正式文件没有被覆盖。
  • 实例不一致风险:你更新时间戳操作的是全局的users实例,但写入XML时用的是方法参数传入的dt,如果这两个不是同一个DataTable实例,你修改users完全不会影响dt的内容,写入的永远是最初的旧数据。

修复方案

  • 恢复线程安全控制:所有读写users/dt的逻辑(包括更新时间戳、写入XML)全部放在lock(users)块内执行,避免并发修改问题。
  • 修正异步写法:
    1. 将async void WriteTask改为async Task WriteTask,方便外层捕获异常。
    2. 移除手动创建Task的逻辑,直接串行执行更新、写入方法。
    3. 将Thread.Sleep(30000)替换为await Task.Delay(30000),避免线程阻塞。
  • 修正时间戳逻辑:每次进入UvalClockTaksAsync时再实时获取当前时间赋值给TimeCurrent,不要使用提前缓存的时间值。
  • 提交DataTable更改:每次修改完所有行之后调用dt.AcceptChanges(),确保修改被提交到行的当前版本,写入XML时能取到最新值。
  • 增加异常感知:每次程序运行后主动检查log.txt的内容,确认有没有文件写入、替换的报错,若有文件占用问题可以加重试逻辑。
  • 确认实例一致性:检查传入WriteTask的dt参数是否就是全局的users实例,保证修改和写入的是同一个对象。

内容的提问来源于stack exchange,提问作者IllSkillz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:06:10