C# Polly文件操作重试 C#如何为不稳定的文件IO增加重试策略

为什么直接用 Polly.Wrap 会失败

文件 IO 操作(比如 File.ReadAllTextFileStream.Write)通常抛出的是 IOExceptionUnauthorizedAccessExceptionDirectoryNotFoundException,但 Polly 默认策略只捕获 Exception 基类——这本身没问题;真正踩坑的是:**某些文件异常(如被其他进程锁定)在重试瞬间仍会立即复现,且没有“冷却时间”或“退避逻辑”,导致重试形同虚设**。

更隐蔽的问题是:Polly 的 PolicyWrap 如果嵌套了 RetryCircuitBreaker,而你没在重试前释放文件句柄(比如忘了 usingDispose),下次重试时可能因句柄未释放继续报 IOException: The process cannot access the file...

实操建议:

如何写一个安全的重试型 File.ReadAllText

直接对 File.ReadAllText(path) 套 Polly 是危险的——它内部可能已打开文件但没暴露流供你控制生命周期。正确做法是自己构造可重试的流读取逻辑。

示例(使用 FileStream + StreamReader):

var retryPolicy = Policy
    .Handle<IOException>()
    .Or<UnauthorizedAccessException>()
    .WaitAndRetryAsync(
        retryCount: 3,
        sleepDurationProvider: (retryAttempt) => 
            TimeSpan.FromMilliseconds(100 * Math.Pow(2, retryAttempt))
    );

string content = await retryPolicy.ExecuteAsync(async () => { using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous); using var sr = new StreamReader(fs); return await sr.ReadToEndAsync(); });

关键点:

Directory.CreateDirectory 重试要注意什么

Directory.CreateDirectory 看似幂等,但在网络路径或权限瞬变场景下仍可能失败。它的典型错误是 UnauthorizedAccessExceptionIOException(如父目录不存在且无法创建)。

但它有个隐藏特性:**即使抛异常,部分中间目录可能已被创建成功**。所以重试前不能简单“再试一次”,得先检查目标路径是否存在。

实操建议:

异步文件写入(WriteAllTextAsync)怎么加重试

File.WriteAllTextAsync 底层会创建新文件并覆盖,但如果目标文件正被记事本、Excel 或杀毒软件占用,就会抛 IOException。注意:它不会自动处理“文件存在但只读”的情况——那会抛 UnauthorizedAccessException,需额外捕获。

推荐写法(带存在性与只读处理):

var policy = Policy
    .Handle<IOException>()
    .Or<UnauthorizedAccessException>()
    .WaitAndRetryAsync(2, _ => TimeSpan.FromMilliseconds(50));

await policy.ExecuteAsync(async () => { if (File.Exists(path) && (File.GetAttributes(path) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { File.SetAttributes(path, FileAttributes.Normal); } await File.WriteAllTextAsync(path, content); });

容易忽略的点:

重试不是万能胶水,文件 IO 的不确定性主要来自外部系统(OS 锁、防病毒扫描、网络延迟)。最可靠的策略永远是:先检查再操作,失败后等一会儿再检查,而不是无脑重试

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。