init commit
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user