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

局域网多机通过VSTO同时访问共享XML文件的解决方案咨询

局域网多进程共享XML文件写入方案(无异步/队列/数据库)

核心思路

针对20台设备同时写入共享XML的场景,用文件排他锁+后台线程重试的方案,既保证文件操作的原子性,又不会阻塞Word主程序的UI线程。

关键实现建议

  • 排他锁控制并发:打开文件时使用FileShare.None参数,确保同一时间只有一个进程能写入文件,其他进程触发异常后通过重试机制等待锁释放。
  • 后台线程执行写入:把文件写入逻辑放到后台线程(比如ThreadPool),避免阻塞Word的UI操作,满足不阻塞程序的需求。
  • 缩短锁持有时间:尽量快速完成XML的读取、修改、写入操作,减少其他进程等待时长,降低冲突概率。
  • 本地缓存兜底:如果多次重试仍写入失败,将待写入的数据暂存到本地临时文件,下次Word启动时再尝试同步到共享XML,避免数据丢失。

C#代码片段(适配VSTO加载项)

using System;
using System.IO;
using System.Threading;
using System.Xml.Linq;

namespace WordVSTOAddIn
{
    public class SharedXmlWriter
    {
        private const string SharedXmlPath = @"\\YourServer\SharedFolder\Stats.xml";
        private const int MaxRetryCount = 5;
        private const int RetryDelayMs = 1000; // 每次重试间隔1秒

        // 调用此方法提交统计数据,不会阻塞Word主线程
        public void SubmitStatsAsync(string deviceId, string statsData)
        {
            // 用ThreadPool把写入逻辑放到后台线程
            ThreadPool.QueueUserWorkItem(state =>
            {
                var stats = (Tuple<string, string>)state;
                WriteStatsToSharedXml(stats.Item1, stats.Item2);
            }, Tuple.Create(deviceId, statsData));
        }

        private void WriteStatsToSharedXml(string deviceId, string statsData)
        {
            int retryCount = 0;
            bool writeSuccess = false;

            while (retryCount < MaxRetryCount && !writeSuccess)
            {
                try
                {
                    XDocument xmlDoc;

                    // 打开或创建XML文件,使用排他锁
                    using (var fs = new FileStream(SharedXmlPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                    {
                        if (fs.Length == 0)
                        {
                            // 文件为空,初始化根节点
                            xmlDoc = new XDocument(new XElement("DeviceStats"));
                        }
                        else
                        {
                            xmlDoc = XDocument.Load(fs);
                        }

                        // 添加新的统计节点
                        var newStat = new XElement("DeviceStat",
                            new XAttribute("DeviceId", deviceId),
                            new XAttribute("Timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                            new XElement("Data", statsData));

                        xmlDoc.Root.Add(newStat);

                        // 回到文件开头,覆盖写入
                        fs.Seek(0, SeekOrigin.Begin);
                        xmlDoc.Save(fs);
                        // 截断多余的字节(如果文件原来更长)
                        fs.SetLength(fs.Position);

                        writeSuccess = true;
                    }
                }
                catch (IOException)
                {
                    // 捕获文件被占用的异常,重试
                    retryCount++;
                    Thread.Sleep(RetryDelayMs);
                }
                catch (Exception ex)
                {
                    // 其他异常,比如XML格式错误,记录日志并退出
                    File.AppendAllText(@"C:\Temp\XmlWriteError.log", $"{DateTime.Now}: {ex.Message}\r\n");
                    break;
                }
            }

            if (!writeSuccess)
            {
                // 多次重试失败,缓存到本地临时文件
                var tempPath = Path.Combine(Path.GetTempPath(), $"StatsCache_{deviceId}_{Guid.NewGuid()}.xml");
                var cacheDoc = new XDocument(new XElement("CachedStat",
                    new XAttribute("DeviceId", deviceId),
                    new XAttribute("Timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                    new XElement("Data", statsData)));
                cacheDoc.Save(tempPath);
            }
        }

        // 可选:Word启动时同步本地缓存到共享XML
        public void SyncCachedStatsOnStartup()
        {
            var tempDir = Path.GetTempPath();
            var cacheFiles = Directory.GetFiles(tempDir, "StatsCache_*.xml");

            foreach (var file in cacheFiles)
            {
                try
                {
                    var cacheDoc = XDocument.Load(file);
                    var deviceId = cacheDoc.Root.Attribute("DeviceId")?.Value;
                    var statsData = cacheDoc.Root.Element("Data")?.Value;

                    if (!string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(statsData))
                    {
                        WriteStatsToSharedXml(deviceId, statsData);
                        File.Delete(file); // 同步成功后删除缓存文件
                    }
                }
                catch (Exception ex)
                {
                    File.AppendAllText(@"C:\Temp\CacheSyncError.log", $"{DateTime.Now}: {ex.Message}\r\n");
                }
            }
        }
    }
}

使用说明

  1. 把SharedXmlPath替换为你的共享文件夹XML路径。
  2. 在VSTO加载项的ThisAddIn_Startup方法里,调用SyncCachedStatsOnStartup()同步本地缓存。
  3. 需要提交统计数据时,调用SubmitStatsAsync(deviceId, statsData),比如在Word关闭事件或者某个操作完成后。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:12:26