Search code examples
.net.net-3.5file

Wait until file is unlocked in .NET


What's the simplest way of blocking a thread until a file has been unlocked and is accessible for reading and renaming? For example, is there a WaitOnFile() somewhere in the .NET Framework?

I have a service that uses a FileSystemWatcher to look for files that are to be transmitted to an FTP site, but the file created event fires before the other process has finished writing the file.

The ideal solution would have a timeout period so the thread doesn't hang forever before giving up.

Edit: After trying out some of the solutions below, I ended up changing the system so that all files wrote to Path.GetTempFileName(), then performed a File.Move() to the final location. As soon as the FileSystemWatcher event fired, the file was already complete.


Solution

  • This was the answer I gave on a related question:

        /// <summary>
        /// Blocks until the file is not locked any more.
        /// </summary>
        /// <param name="fullPath"></param>
        bool WaitForFile(string fullPath)
        {
            int numTries = 0;
            while (true)
            {
                ++numTries;
                try
                {
                    // Attempt to open the file exclusively.
                    using (FileStream fs = new FileStream(fullPath,
                        FileMode.Open, FileAccess.ReadWrite, 
                        FileShare.None, 100))
                    {
                        fs.ReadByte();
    
                        // If we got this far the file is ready
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log.LogWarning(
                       "WaitForFile {0} failed to get an exclusive lock: {1}", 
                        fullPath, ex.ToString());
    
                    if (numTries > 10)
                    {
                        Log.LogWarning(
                            "WaitForFile {0} giving up after 10 tries", 
                            fullPath);
                        return false;
                    }
    
                    // Wait for the lock to be released
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            Log.LogTrace("WaitForFile {0} returning true after {1} tries",
                fullPath, numTries);
            return true;
        }