70 lines
2.8 KiB
C#
70 lines
2.8 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.IO;
|
|
using SimpleCore.Library;
|
|
|
|
namespace StandardScene.CommonTools
|
|
{
|
|
/// <summary>
|
|
/// 按文件路径串行化读写,保证高并发下对同一文件的更新原子、不覆盖其他记录。
|
|
/// 调用方在委托中完成“读当前内容 → 修改 → 返回新内容”,由本类负责加锁与写回。
|
|
/// </summary>
|
|
public static class AtomicFileUpdateHelper
|
|
{
|
|
private static readonly ConcurrentDictionary<string, object> PathLocks = new ConcurrentDictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
/// <summary>
|
|
/// 对指定路径执行原子更新:在持锁下读取当前文件内容,调用 update 得到新内容并写回。
|
|
/// 不修改其他记录时,应在 update 中仅变更需要变更的条目后返回完整内容。
|
|
/// </summary>
|
|
/// <param name="filePath">文件完整路径</param>
|
|
/// <param name="update">接收当前文件文本(若文件不存在则为 null),返回要写回的新文本;返回 null 表示不写入</param>
|
|
public static void ExecuteAtomicUpdate(string filePath, Func<string, string> update)
|
|
{
|
|
if (string.IsNullOrEmpty(filePath))
|
|
throw new ArgumentNullException(nameof(filePath));
|
|
if (update == null)
|
|
throw new ArgumentNullException(nameof(update));
|
|
|
|
var lockObj = PathLocks.GetOrAdd(filePath, _ => new object());
|
|
lock (lockObj)
|
|
{
|
|
string current = null;
|
|
try
|
|
{
|
|
if (File.Exists(filePath))
|
|
current = File.ReadAllText(filePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Diagnosis.Log($"AtomicFileUpdate read error: {filePath}, {ex.Message}", "AtomicFileUpdate", true);
|
|
throw;
|
|
}
|
|
|
|
string newContent = update(current);
|
|
if (newContent == null)
|
|
return;
|
|
|
|
var dir = Path.GetDirectoryName(filePath);
|
|
if (!string.IsNullOrEmpty(dir))
|
|
Directory.CreateDirectory(dir);
|
|
|
|
try
|
|
{
|
|
var tempPath = filePath + ".tmp";
|
|
File.WriteAllText(tempPath, newContent);
|
|
if (File.Exists(filePath))
|
|
File.Replace(tempPath, filePath, null);
|
|
else
|
|
File.Move(tempPath, filePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Diagnosis.Log($"AtomicFileUpdate write error: {filePath}, {ex.Message}", "AtomicFileUpdate", true);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|