有没有什么方法可以不使用try/catch块来检查文件是否被锁定?
现在,我所知道的唯一方法是打开文件并捕获任何System.IO.IOException。
有没有什么方法可以不使用try/catch块来检查文件是否被锁定?
现在,我所知道的唯一方法是打开文件并捕获任何System.IO.IOException。
当前回答
当我遇到类似的问题时,我完成了以下代码:
public class FileManager
{
private string _fileName;
private int _numberOfTries;
private int _timeIntervalBetweenTries;
private FileStream GetStream(FileAccess fileAccess)
{
var tries = 0;
while (true)
{
try
{
return File.Open(_fileName, FileMode.Open, fileAccess, Fileshare.None);
}
catch (IOException e)
{
if (!IsFileLocked(e))
throw;
if (++tries > _numberOfTries)
throw new MyCustomException("The file is locked too long: " + e.Message, e);
Thread.Sleep(_timeIntervalBetweenTries);
}
}
}
private static bool IsFileLocked(IOException exception)
{
int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
return errorCode == 32 || errorCode == 33;
}
// other code
}
其他回答
然后,在这两行之间,另一个进程可以很容易地锁定文件,给您带来您一开始试图避免的相同问题:异常。
但是,通过这种方式,您将知道问题是暂时的,并稍后重试。(例如,您可以编写一个线程,如果在尝试写入时遇到锁,则会不断重试,直到锁消失。)
另一方面,IOException本身还不够特定,以至于锁定是导致IO失败的原因。可能有一些不是暂时的原因。
您还可以检查是否有任何进程正在使用此文件,并像安装程序一样显示必须关闭才能继续的程序列表。
public static string GetFileProcessName(string filePath)
{
Process[] procs = Process.GetProcesses();
string fileName = Path.GetFileName(filePath);
foreach (Process proc in procs)
{
if (proc.MainWindowHandle != new IntPtr(0) && !proc.HasExited)
{
ProcessModule[] arr = new ProcessModule[proc.Modules.Count];
foreach (ProcessModule pm in proc.Modules)
{
if (pm.ModuleName == fileName)
return proc.ProcessName;
}
}
}
return null;
}
我最后做的是:
internal void LoadExternalData() {
FileStream file;
if (TryOpenRead("filepath/filename", 5, out file)) {
using (file)
using (StreamReader reader = new StreamReader(file)) {
// do something
}
}
}
internal bool TryOpenRead(string path, int timeout, out FileStream file) {
bool isLocked = true;
bool condition = true;
do {
try {
file = File.OpenRead(path);
return true;
}
catch (IOException e) {
var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
isLocked = errorCode == 32 || errorCode == 33;
condition = (isLocked && timeout > 0);
if (condition) {
// we only wait if the file is locked. If the exception is of any other type, there's no point on keep trying. just return false and null;
timeout--;
new System.Threading.ManualResetEvent(false).WaitOne(1000);
}
}
}
while (condition);
file = null;
return false;
}
您可以在感兴趣的文件区域上通过互操作调用LockFile。这将不会抛出异常,如果它成功,你将对文件的那一部分(由你的进程持有)拥有一个锁,这个锁将一直持有,直到你调用UnlockFile或你的进程死亡。
在Powershell中也是一样
function Test-FileOpen
{
Param
([string]$FileToOpen)
try
{
$openFile =([system.io.file]::Open($FileToOpen,[system.io.filemode]::Open))
$open =$true
$openFile.close()
}
catch
{
$open = $false
}
$open
}