您的位置:首页 >C#文件IO重试策略实现方法
发布于2026-03-13 阅读(0)
扫一扫,手机访问

文件 IO 操作(比如 File.ReadAllText、FileStream.Write)通常抛出的是 IOException、UnauthorizedAccessException 或 DirectoryNotFoundException,但 Polly 默认策略只捕获 Exception 基类——这本身没问题;真正踩坑的是:**某些文件异常(如被其他进程锁定)在重试瞬间仍会立即复现,且没有“冷却时间”或“退避逻辑”,导致重试形同虚设**。
更隐蔽的问题是:Polly 的 PolicyWrap 如果嵌套了 Retry 和 CircuitBreaker,而你没在重试前释放文件句柄(比如忘了 using 或 Dispose),下次重试时可能因句柄未释放继续报 IOException: The process cannot access the file...。
实操建议:
Policy.Handle().Or() 显式声明要捕获的异常类型,避免漏掉常见文件锁异常WaitAndRetryAsync + 指数退避(如 Backoff.DecorrelatedJitterBackoffV2),不能只用固定间隔using 或确保 Dispose 被调用,否则重试只会让问题恶化直接对 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();
});
关键点:
FileStream 创建和 StreamReader 初始化都放在 ExecuteAsync 内部,确保每次重试都是全新句柄FileOptions.Asynchronous,避免同步阻塞干扰重试调度4096)建议设为 4KB 或 8KB,太小会放大 I/O 开销,太大无益Directory.CreateDirectory 看似幂等,但在网络路径或权限瞬变场景下仍可能失败。它的典型错误是 UnauthorizedAccessException 或 IOException(如父目录不存在且无法创建)。
但它有个隐藏特性:**即使抛异常,部分中间目录可能已被创建成功**。所以重试前不能简单“再试一次”,得先检查目标路径是否存在。
实操建议:
.CanRetryImmediately((ex, ct) => !Directory.Exists(path)) 判断(需自定义策略逻辑,或手动加前置检查)\\server\share\folder),必须确保运行账户有网络访问权限,Polly 无法绕过这个限制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);
});
容易忽略的点:
File.SetAttributes 本身也可能失败(如权限不足),所以它应该放在重试范围内,而不是前置一次性操作FileStream 分块写 + FlushAsync,避免单次大写入失败后全部重放Path.GetTempFileName(),否则每次重试都会留垃圾文件重试不是万能胶水,文件 IO 的不确定性主要来自外部系统(OS 锁、防病毒扫描、网络延迟)。最可靠的策略永远是:先检查再操作,失败后等一会儿再检查,而不是无脑重试。
上一篇:电脑远程桌面怎么设置
下一篇:苹果手机如何开启朗读功能?
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9