有没有办法检查文件是不是正在使用?

Posted

技术标签:

【中文标题】有没有办法检查文件是不是正在使用?【英文标题】:Is there a way to check if a file is in use?有没有办法检查文件是否正在使用? 【发布时间】:2010-10-26 23:07:00 【问题描述】:

我正在用 C# 编写一个需要重复访问 1 个图像文件的程序。大多数情况下它可以工作,但如果我的计算机运行速度很快,它会在文件保存回文件系统之前尝试访问文件并抛出错误:

“文件正在被另一个进程使用”

我想找到解决这个问题的方法,但我所有的谷歌搜索都只通过使用异常处理产生了创建检查。这违反了我的宗教信仰,所以我想知道是否有人有更好的方法?

【问题讨论】:

好的,您可以通过检查系统上所有打开的句柄来测试它。但是,由于 Windows 是一个多任务操作系统,有可能在您运行代码以确定文件是否打开并且您认为它没有打开之后,进程代码开始使用该文件,然后当您尝试使用它,你会收到一个错误。但是,先检查并没有错;只是不要假设它在你真正需要它的时候没有被使用。 但仅针对这个特定问题;我建议不要检查文件句柄,而只是尝试一些预设的次数,比如在失败前 3-5 次。 你的哲学对异常的理解很差。大多数人认为例外意味着神圣的废话 - 厄运 - 错误 - 死 - 死 - 死。当异常意味着……异常。这意味着发生了需要“处理”(或解释)的异常情况。也许您想继续重试数据访问,也许用户需要知道您无法获得连接。你做什么工作?您处理 ConnectionFailedException 并通知用户,所以他们可能会在一小时后停止尝试,并注意到电缆已拔下。 操作员 Lee Louviere 不喜欢处理异常。如果您可以轻松地使用 filexists 方法来了解文件是否存在,那么存在什么类似的命令来了解您要使用的文件是否正在使用中?事实上,我相信这是操作员真正要问的问题。 @webs 一些例外只是生活中的事实。使用 File.Exists() 很好,但就像答案说的那样,并不总是可以避免它们。例如,一个文件可能在您检查它是否存在和您实际打开它之间存在。在大多数情况下,这个无限期已经足够好了,但没有任何保证,因此异常处理程序应该包装调用以打开它,等等。 【参考方案1】:

对此解决方案的更新说明:使用FileAccess.ReadWrite 检查只读文件将失败,因此已修改解决方案以使用FileAccess.Read 进行检查。

原文: 在过去的几年里我一直在使用这个代码,我没有遇到任何问题。

了解您对使用异常的犹豫,但您不能一直避免它们:

protected virtual bool IsFileLocked(FileInfo file)

    try
    
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        
            stream.Close();
        
    
    catch (IOException)
    
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    

    //file is not locked
    return false;

【讨论】:

这是一个很好的解决方案,但我有一个评论 - 你可能不想用访问模式 FileAccess.Read 打开文件,因为如果文件碰巧是只读的,ReadWrite 总是会失败。 -1。这是一个糟糕的答案,因为在 IsFileLocked 中关闭文件之后,并且在您的线程有机会打开它之前,该文件可能被另一个线程/进程锁定。 我认为这是一个很好的答案。我将其用作extension method á la public static bool IsLocked(this FileInfo file) /*...*/ @ChrisW:您可能想知道发生了什么。不要惊慌。你只是受到了 Daily WTF 社区的愤怒:thedailywtf.com/Comments/… @ChrisW 为什么这是一件坏事。这个社区在这里指出好的和坏的答案。如果一群专业人士注意到这是一件坏事,并加入反对票,那么该网站就是 WAI。在你否定之前,如果你读了那篇文章,他们会说“赞成正确的答案”而不是反对错误的答案。您是否也希望他们在 cmets 中解释他们的赞成票。感谢您向我介绍另一个好网站!【参考方案2】:

您可能会因此受到线程竞争状况的影响,有记录的示例将其用作安全漏洞。如果您检查该文件是否可用,然后尝试使用它,您可能会在此时抛出,恶意用户可能会使用它来强制和利用您的代码。

您最好的选择是尝试获取文件句柄的 try catch / finally。

try

   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   
        // File/Stream manipulating code here
   
 catch 
  //check here why it failed and ask user to retry if the file is in use.

【讨论】:

+1。没有 100% 安全的方法来“了解文件是否正在使用”,因为在您进行检查后的几毫秒内,该文件可能不再使用,反之亦然。相反,您只需打开文件并在没有异常的情况下使用它。 太糟糕了 .NET 不支持 CAS。类似于 TryOpenFile(Ref FileHandle) 返回成功/失败。应该始终有一种解决方法,而不是仅依赖异常处理。我想知道 Microsoft Office 是如何做到的。 这里要理解的关键是这个 API 只是使用 windows API 来获取文件句柄。因此,他们需要翻译从 C API 接收到的错误代码,并将其包装到要抛出的异常中。我们在.Net 中有异常处理,所以为什么不使用它。这样您就可以在代码中编写干净的正向路径,并将错误处理留在单独的代码路径中。 using 语句是为了确保在我完成后关闭流。我想你会发现 using() 的字符比 try finally obj.Dispose() 少。您还会发现您现在需要在 using 语句之外声明您的对象引用,这需要更多的输入。如果你有一个明确的接口,你也必须强制转换。最后,您希望尽快处理,并且最终逻辑可能具有 UI 或任何其他与调用 IDispose 无关的长时间运行的操作。 @HarryJohnston // File/Stream manipulating code here - 你应该在 try 块内使用文件(读/写/等),从而避免另一个进程可以在之间锁定文件的竞争条件检查和打开 - 因为检查和打开是这里的一个原子操作。【参考方案3】:

使用它来检查文件是否被锁定:

using System.IO;
using System.Runtime.InteropServices;
internal static class Helper

const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;

private static bool IsFileLocked(Exception exception)

    int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
    return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;


internal static bool CanReadFile(string filePath)

    //Try-Catch so we dont crash the program and can check the exception
    try 
        //The "using" is important because FileStream implements IDisposable and
        //"using" will avoid a heap exhaustion situation when too many handles  
        //are left undisposed.
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) 
            if (fileStream != null) fileStream.Close();  //This line is me being overly cautious, fileStream will never be null unless an exception occurs... and I know the "using" does it but its helpful to be explicit - especially when we encounter errors - at least for me anyway!
        
    
    catch (IOException ex) 
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex)) 
            // do something, eg File.Copy or present the user with a MsgBox - I do not recommend Killing the process that is locking the file
            return false;
        
    
    finally
     
    return true;


出于性能原因,我建议您在同一操作中读取文件内容。以下是一些示例:

public static byte[] ReadFileBytes(string filePath)

    byte[] buffer = null;
    try
    
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
                sum += count;  // sum is a buffer offset for next reading

            fileStream.Close(); //This is not needed, just me being paranoid and explicitly releasing resources ASAP
        
    
    catch (IOException ex)
    
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        
            // do something? 
        
    
    catch (Exception ex)
    
    
    finally
    
    
    return buffer;


public static string ReadFileTextWithEncoding(string filePath)

    string fileContents = string.Empty;
    byte[] buffer;
    try
    
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
            
                sum += count;  // sum is a buffer offset for next reading
            

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            //Depending on the encoding you wish to use - I'll leave that up to you
            fileContents = System.Text.Encoding.Default.GetString(buffer);
        
    
    catch (IOException ex)
    
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        
            // do something? 
        
    
    catch (Exception ex)
    
    
    finally
          
    return fileContents;


public static string ReadFileTextNoEncoding(string filePath)

    string fileContents = string.Empty;
    byte[] buffer;
    try
    
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0) 
            
                sum += count;  // sum is a buffer offset for next reading
            

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            char[] chars = new char[buffer.Length / sizeof(char) + 1];
            System.Buffer.BlockCopy(buffer, 0, chars, 0, buffer.Length);
            fileContents = new string(chars);
        
    
    catch (IOException ex)
    
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        
            // do something? 
        
    
    catch (Exception ex)
    
    
    finally
    
    

    return fileContents;

自己试试吧:

byte[] output1 = Helper.ReadFileBytes(@"c:\temp\test.txt");
string output2 = Helper.ReadFileTextWithEncoding(@"c:\temp\test.txt");
string output3 = Helper.ReadFileTextNoEncoding(@"c:\temp\test.txt");

【讨论】:

如果那里没有那么多“神奇数字”,我会投票赞成en.wikipedia.org/wiki/Magic_number_(programming) 我指的是错误代码比较,而不是位移。虽然现在你提到它...... 你的 Catch 应该是 IOException,而不是一般的 Exception,然后是类型测试。 @JeremyThompson 遗憾的是,您将特定的 IOException 放在了一般的后面。一般的人会抓住所有经过的东西,而具体的IOException将永远是孤独的。只需交换两者即可。 我喜欢这个解决方案。另一个建议:在 catch 作为 if(IsFileLocked(ex)) 的 else 我会抛出 ex。然后,这将通过抛出异常来处理文件不存在(或任何其他 IOException)的情况。【参考方案4】:

按预期使用异常。接受该文件正在使用中,然后重试,直到您的操作完成。这也是最有效的,因为您不会浪费任何循环在执行之前检查状态。

使用下面的函数,例如

TimeoutFileAction(() =>  System.IO.File.etc...; return null;  );

2秒后超时的可重用方法

private T TimeoutFileAction<T>(Func<T> func)

    var started = DateTime.UtcNow;
    while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
    
        try
        
            return func();                    
        
        catch (System.IO.IOException exception)
        
            //ignore, or log somewhere if you want to
        
    
    return default(T);

【讨论】:

【参考方案5】:

也许您可以使用 FileSystemWatcher 并注意 Changed 事件。

我自己没有使用过,但可能值得一试。如果在这种情况下文件系统监视程序变得有点重,我会选择 try/catch/sleep 循环。

【讨论】:

使用 FileSystemWatcher 没有帮助,因为 Created 和 Changed 事件在文件创建/更改开始时引发。即使是小文件也需要更多的时间来由操作系统写入和关闭,而不是 .NET 应用程序需要通过 FileSystemEventHandler 回调运行。这太可悲了,但除了估计访问文件之前的等待时间或遇到异常循环之外别无选择...... FileSystemWatcher 不能很好地同时处理大量更改,所以要小心。 顺便说一句,你们在调试和观看 MS 调用他们自己的 FSW“FileSystemWather”的线程时注意到了吗?到底什么是水? 正是我遇到了这个问题,因为带有 FileSystemWatcher 的 Windows 服务尝试在进程关闭之前读取文件。【参考方案6】:

您可以返回一个任务,它会在它可用时立即为您提供流。这是一个简化的解决方案,但它是一个很好的起点。它是线程安全的。

private async Task<Stream> GetStreamAsync()

    try
    
        return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
    
    catch (IOException)
    
        await Task.Delay(TimeSpan.FromSeconds(1));
        return await GetStreamAsync();
    

你可以像往常一样使用这个流:

using (var stream = await FileStreamGetter.GetStreamAsync())

    Console.WriteLine(stream.Length);

【讨论】:

GetStreamAsync() 的递归中堆栈溢出多少秒? @CADbloke,你提出了一个很好的观点。事实上,如果文件长时间不可用,我的示例可能会出现堆栈溢出异常。与此答案***.com/questions/4513438/… 相关,它可能会在 5 小时内引发异常。 与您的用例相关,如果假设 10 次尝试读取文件失败,则最好抛出 I/O 异常。另一种策略可能是在 10 次尝试失败后增加一秒钟的等待时间。您也可以混合使用两者。 我会(并且会)简单地提醒用户文件被锁定。他们通常会自己锁定它,因此他们可能会对此采取一些措施。或者不。 在某些情况下,您需要使用重试策略,因为文件可能尚未准备好。想象一个桌面应用程序下载某个临时文件夹中的图像。应用程序开始下载,同时您在文件资源管理器中打开此文件夹。 Windows 想要立即创建缩略图并锁定文件。同时,您的应用程序会尝试将锁定的图像替换到其他位置。如果您不使用重试策略,您将收到异常。【参考方案7】:

上面接受的答案会遇到一个问题,即如果文件已打开以使用 FileShare.Read 模式进行写入,或者文件具有只读属性,则代码将不起作用。这个修改后的解决方案最可靠,需要牢记两点(对于公认的解决方案也是如此):

    它不适用于以写入共享模式打开的文件 这没有考虑线程问题,因此您需要将其锁定或单独处理线程问题。

记住以上内容,这会检查文件是锁定写入还是锁定以防止读取

public static bool FileLocked(string FileName)

    FileStream fs = null;

    try
    
        // NOTE: This doesn't handle situations where file is opened for writing by another process but put into write shared mode, it will not throw an exception and won't show it as write locked
        fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // If we can't open file for reading and writing then it's locked by another process for writing
    
    catch (UnauthorizedAccessException) // https://msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx
    
        // This is because the file is Read-Only and we tried to open in ReadWrite mode, now try to open in Read only mode
        try
        
            fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);
        
        catch (Exception)
        
            return true; // This file has been locked, we can't even open it to read
        
    
    catch (Exception)
    
        return true; // This file has been locked
    
    finally
    
        if (fs != null)
            fs.Close();
    
    return false;

【讨论】:

仍然存在与已接受答案相同的问题 - 它仅告诉您文件是否在在某个特定时刻被另一个进程锁定,这不是有用的信息。到函数返回时,结果可能已经过时了! 是的,只能在任何给定时间检查(或订阅事件),这种方法优于公认的解决方案的优点是它可以检查只读属性和写入锁定而不返回误报。【参考方案8】:

我最近遇到了这个问题,发现了这个:https://docs.microsoft.com/en-us/dotnet/standard/io/handling-io-errors。

在这里,Microsoft 描述了以下方法来检查 IOException 是否是由于文件锁定引起的:

catch (IOException e) when ((e.HResult & 0x0000FFFF) == 32 ) 
    Console.WriteLine("There is a sharing violation.");

【讨论】:

迄今为止的最佳答案。仅适用于锁定文件,不适用于一般 IO 异常。【参考方案9】:
static bool FileInUse(string path)
    
        try
        
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            
                fs.CanWrite
            
            return false;
        
        catch (IOException ex)
        
            return true;
        
    

string filePath = "C:\\Documents And Settings\\yourfilename";
bool isFileInUse;

isFileInUse = FileInUse(filePath);

// Then you can do some checking
if (isFileInUse)
   Console.WriteLine("File is in use");
else
   Console.WriteLine("File is not in use");

希望这会有所帮助!

【讨论】:

您执行的实际检查很好;把它放在一个函数中是有误导性的。您不想在打开文件之前使用这样的功能。在函数内部,文件被打开、检查和关闭。然后程序员假设该文件仍然可以使用并尝试打开它以供使用。这很糟糕,因为它可能被另一个排队打开此文件的进程使用和锁定。在第一次打开(用于检查)和第二次打开(用于使用)之间,操作系统可能已经取消了您的进程并可能正在运行另一个进程。【参考方案10】:

除了工作 3-liners 并且仅供参考:如果您想要完整的信息 - Microsoft 开发中心有一个小项目:

https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4

现在可在以下位置找到: https://github.com/TacticalHorse/LockFinder/blob/master/LockFinder.cs

来自简介:

在 .NET Framework 4.0 中开发的 C# 示例代码将有助于 找出锁定文件的进程。 rstrtmgr.dll 中包含的 RmStartSession 函数已 用于创建重启管理器会话并根据返回 结果创建了一个 Win32Exception 对象的新实例。后 通过以下方式将资源注册到重新启动管理器会话 RmRegisterRescorces函数,调用RmGetList函数进行检查 通过枚举哪些应用程序正在使用特定文件 RM_PROCESS_INFO 数组。

它通过连接到“重新启动管理器会话”来工作。

重新启动管理器使用在会话中注册的资源列表来 确定必须关闭和重新启动哪些应用程序和服务。 资源可以通过文件名、服务短名称或 描述正在运行的应用程序的 RM_UNIQUE_PROCESS 结构

对于您的特定需求,它可能有点过度设计... 但如果那是想要的,请继续使用 vs-project。

【讨论】:

如果有示例代码,这可能是一个非常有趣的解决方案。您提供的链接现在无效..【参考方案11】:

我知道的唯一方法是使用 Win32 独占锁 API,它不是太快,但是有例子。

大多数人,对于这个问题的简单解决方案,只是尝试/捕获/睡眠循环。

【讨论】:

如果不先打开文件,您将无法使用此 API,此时您不再需要。 薛定谔的档案。【参考方案12】:

据我所知,这里有一些代码与接受的答案相同,但代码更少:

    public static bool IsFileLocked(string file)
    
        try
        
            using (var stream = File.OpenRead(file))
                return false;
        
        catch (IOException)
        
            return true;
                
    

但我认为以以下方式执行此操作更为稳健:

    public static void TryToDoWithFileStream(string file, Action<FileStream> action, 
        int count, int msecTimeOut)
    
        FileStream stream = null;
        for (var i = 0; i < count; ++i)
        
            try
            
                stream = File.OpenRead(file);
                break;
            
            catch (IOException)
            
                Thread.Sleep(msecTimeOut);
            
        
        action(stream);
    

【讨论】:

【参考方案13】:

根据我的经验,您通常希望这样做,然后“保护”您的文件以做一些花哨的事情,然后使用“受保护”的文件。如果您只想像这样使用一个文件,则可以使用 Jeremy Thompson 的答案中解释的技巧。但是,如果您尝试对大量文件执行此操作(例如,当您编写安装程序时),您将受到相当大的伤害。

解决这个问题的一个非常优雅的方法是利用这样一个事实,即如果您的文件系统正在使用其中一个文件,您将不允许您更改文件夹名称。将文件夹保存在同一个文件系统中,它会像一个魅力一样工作。

请注意,您应该了解可以利用这一点的明显方式。毕竟,文件不会被锁定。此外,请注意还有其他原因可能导致您的 Move 操作失败。显然,适当的错误处理 (MSDN) 可以提供帮助。

var originalFolder = @"c:\myHugeCollectionOfFiles"; // your folder name here
var someFolder = Path.Combine(originalFolder, "..", Guid.NewGuid().ToString("N"));

try

    Directory.Move(originalFolder, someFolder);

    // Use files

catch // TODO: proper exception handling

    // Inform user, take action

finally

    Directory.Move(someFolder, originalFolder);

对于单个文件,我会坚持 Jeremy Thompson 发布的锁定建议。

【讨论】:

嗨,由于答案的顺序发生了变化,您能否澄清一下上面对于这个受欢迎的 QA 的读者来说是哪篇文章。谢谢。 @JeremyThompson 你说得对,谢谢,我会编辑这篇文章。我会使用您的解决方案,主要是因为您正确使用了FileShare 并检查了锁。【参考方案14】:

我曾经需要将 PDF 上传到在线备份存档。但如果用户在另一个程序(如 PDF 阅读器)中打开文件,备份将失败。匆忙中,我尝试了该线程中的一些最佳答案,但无法使它们起作用。对我有用的是试图将 PDF 文件移动到 它自己的目录。我发现如果文件在另一个程序中打开,这将失败,如果移动成功,则不需要恢复操作,就像将它移动到单独的目录一样。我想发布我的基本解决方案,以防它可能对其他人的特定用例有用。

string str_path_and_name = str_path + '\\' + str_filename;
FileInfo fInfo = new FileInfo(str_path_and_name);
bool open_elsewhere = false;
try

    fInfo.MoveTo(str_path_and_name);

catch (Exception ex)

    open_elsewhere = true;


if (open_elsewhere)

    //handle case

【讨论】:

【参考方案15】:

您可以使用我的库从多个应用程序访问文件。

您可以从 nuget 安装它:Install-Package Xabe.FileLock

如果您想了解更多信息,请查看 https://github.com/tomaszzmuda/Xabe.FileLock

ILock fileLock = new FileLock(file);
if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))

    using(fileLock)
    
        // file operations here
    

fileLock.Acquire 方法只有在可以为该对象锁定文件独占时才会返回 true。 但是上传文件的应用程序也必须在文件锁定中进行。 如果对象不可访问,方法返回 false。

【讨论】:

要求所有正在使用该文件的进程进行合作。不太可能适用于 OP 的原始问题。【参考方案16】:

我很想看看这是否会触发任何 WTF 反射。我有一个创建并随后从控制台应用程序启动 PDF 文档的过程。但是,我正在处理一个弱点,如果用户要多次运行该进程,生成相同的文件而不先关闭先前生成的文件,应用程序将抛出异​​常并死掉。这是一个相当频繁的情况,因为文件名是基于销售报价编号的。

我决定依靠自动递增的文件版本控制,而不是以这种不优雅的方式失败:

private static string WriteFileToDisk(byte[] data, string fileName, int version = 0)

    try
    
        var versionExtension = version > 0 ? $"_version:000" : string.Empty;
        var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"fileNameversionExtension.pdf");
        using (var writer = new FileStream(filePath, FileMode.Create))
        
            writer.Write(data, 0, data.Length);
        
        return filePath;
    
    catch (IOException)
    
        return WriteFileToDisk(data, fileName, ++version);
    

可能需要对catch 块给予更多关注,以确保我捕捉到正确的 IOException(s)。我可能还会在启动时清除应用存储,因为这些文件无论如何都是临时的。

我意识到这超出了 OP 仅检查文件是否正在使用的问题的范围,但这确实是我到达这里时想要解决的问题,所以也许它对其他人有用。

【讨论】:

【参考方案17】:
retry_possibility:
//somecode here

try

    using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
    
        stream.Close();
    
    //write or open your file here

catch (IOException)

    DialogResult dialogResult = MessageBox.Show("This file is opened by you or another user. Please close it and press retry.\n"+ expFilePath, "File Locked", MessageBoxButtons.RetryCancel);
    if (dialogResult == DialogResult.Retry)
    
        goto retry_possibility;
    
    else if (dialogResult == DialogResult.Cancel)
    
        //do nothing
    

【讨论】:

【参考方案18】:

这样的东西会有帮助吗?

var fileWasWrittenSuccessfully = false;
while (fileWasWrittenSuccessfully == false)

    try
    
        lock (new Object())
        
            using (StreamWriter streamWriter = new StreamWriter("filepath.txt"), true))
            
                streamWriter.WriteLine("text");
            
        

        fileWasWrittenSuccessfully = true;
    
    catch (Exception)
    

    

【讨论】:

【参考方案19】:

尝试将文件移动/复制到临时目录。如果可以,它没有锁,您可以在临时目录中安全地工作而不会获得锁。否则只需尝试在 x 秒内再次移动它。

【讨论】:

@jcolebrand 锁定什么?你抄的那个?还是您放在临时目录中的那个? 如果您复制文件,希望没有其他人在处理它,并且您将使用临时文件,然后有人在您复制后立即锁定它,那么您可能丢失数据。 之前尝试过(将大文件从本地硬盘复制到虚拟服务器上的虚拟驱动器(1 分钟) - 尝试通过 File.Move() 尝试检测复制的结束 - 但是它失败了!现在两个目录中都存在文件......并且它试图在最后复制 3 次......【参考方案20】:

我使用此解决方法,但我在使用 IsFileLocked 函数检查文件锁定和打开文件之间有一个时间跨度。在这个时间跨度内,一些其他线程可以打开文件,所以我会得到 IOException。

所以,我为此添加了额外的代码。在我的情况下,我想加载 XDocument:

        XDocument xDoc = null;

        while (xDoc == null)
        
            while (IsFileBeingUsed(_interactionXMLPath))
            
                Logger.WriteMessage(Logger.LogPrioritet.Warning, "Deserialize can not open XML file. is being used by another process. wait...");
                Thread.Sleep(100);
            
            try
            
                xDoc = XDocument.Load(_interactionXMLPath);
            
            catch
            
                Logger.WriteMessage(Logger.LogPrioritet.Error, "Load working!!!!!");
            
        

你怎么看?我可以改变一些东西吗?也许我根本不需要使用 IsFileBeingUsed 函数?

谢谢

【讨论】:

什么是 IsFileBeingUsed ?关于 IsFileBeingUsed 的源代码? IsFileBeingUsed - 来自已接受的答案。如果您最终想访问该文件,他只是提供了一种使用方法。这个答案没有错。

以上是关于有没有办法检查文件是不是正在使用?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法检查是不是有人收听 dbus 信号?

如何检查文件是不是在 C# 中签名? [关闭]

有没有办法只使用javascript检查一个元素在视口中是不是可见? [复制]

Python + winsound - 检查是不是正在播放音频文件

有没有办法检查子进程是不是仍在运行?

有没有办法检查延迟加载的组件(使用 React.Lazy)是不是已完成加载?