在C#程序里对文件进行读写时,如果目标文件已经被别的进程以独占方式打开,当前代码就会抛出IOException,提示文件正由另一进程使用。这种情况在日志采集、文件监控和多线程处理中十分常见。我们需要判断文件是否正在被占用,并合理处理由此产生的文件独占异常。
如何判断文件是否正在被占用
最简单直接的办法是尝试以独占模式打开文件,若失败则说明文件很可能被占用。下面的方法通过FileStream尝试打开文件,捕获IOException来判断。
using System;
using System.IO;
using System.Runtime.InteropServices;
public static class FileChecker
{
public static bool IsFileLocked(string path)
{
try
{
// 以独占方式打开文件,不允许其他进程读写
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
stream.Close();
}
return false;
}
catch (IOException)
{
// 捕获异常,说明文件被占用或无法访问
return true;
}
}
}
使用FileShare处理文件独占异常
在打开文件时,可以通过FileShare参数控制与其他进程的共享权限。如果希望允许其他进程读取但禁止写入,可以使用FileShare.Read。
using System;
using System.IO;
public class SafeFileReader
{
public static string ReadWithShare(string path)
{
try
{
// 允许其他进程同时读取,但自己只读取
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader reader = new StreamReader(fs))
{
return reader.ReadToEnd();
}
}
catch (IOException ex)
{
// 处理文件独占异常,返回空字符串并记录
Console.WriteLine("文件读取失败:" + ex.Message);
return string.Empty;
}
}
}
轮询重试机制
当文件只是短时间被占用时,可以采用重试策略,等待一段时间后再次尝试操作。
using System;
using System.IO;
using System.Threading;
public class RetryFileWriter
{
public static void WriteWithRetry(string path, string content, int retryCount = 5)
{
for (int i = 0; i < retryCount; i++)
{
try
{
using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.None))
using (StreamWriter writer = new StreamWriter(fs))
{
writer.Write(content);
}
return;
}
catch (IOException)
{
// 文件被占用,等待后再试
Thread.Sleep(200);
}
}
throw new IOException("多次重试后仍无法写入文件");
}
}
常见错误与注意事项
- 不要忽略IOException,应区分文件不存在与文件被占用。
- 使用using语句确保FileStream及时释放,避免自己造成占用。
- 在多线程中操作同一文件时,统一FileShare策略。
通过上述方式,我们可以在C#中准确判断文件是否正在被占用,并采用共享控制或重试机制处理文件独占异常,从而提高程序的健壮性。