Click here to Skip to main content
14,540,587 members

FileSystemWatcher vs Locked Files

Rate this:
4.75 (6 votes)
Please Sign up or sign in to vote.
4.75 (6 votes)
7 Dec 2017CPOL
You monitor a folder for new files with FileSystemWatcher and try to move those them on arrival. You get an IOException: ...being used by another process. The copying had not finished. Here, I offer a fairly robust solution to this.


You’ve just written your nice shiny new application to monitor a folder for new files arriving and added the code to send that file off somewhere else and delete it. Perhaps you even spent some time packaging it in a nice Windows Service. It probably behaved well during debugging. You move it into a test environment and let the manual testers loose. They copy a file, your eager file watcher spots the new file as soon as it starts writing and does the funky stuff and BANG!… an IOException:

The process cannot access the file X because it is being used by another process.

The copying had not finished before the event fired. It doesn’t even have to be a large file as your super awesome watcher is just so efficient.

A Solution

  1. When a file system event occurs, store its details in Memory Cache for X amount of time
  2. Setup a callback, which will execute when the event expires from Memory Cache
  3. In the callback, check the file is available for write operations
  4. If it is, then get on with the intended file operation
  5. Else, put it back in Memory Cache for X time and repeat the above steps

It would make sense to track and limit the number of retry attempts to get a lock on the file.

Code Snippets

I’ve built this on top of the code discussed in a previous post on dealing with multiple FileSystemWatcher events.

The complete code for this example solution can be found here.

When a file system event is handled, store the file details and the retry count, using a simple POCO, in MemoryCache with a timer of, something like 60 seconds:

private void OnCreated(object source, FileSystemEventArgs e)
    _cacheItemPolicy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(CacheTimeSeconds);

    var fileData = new CacheItemValue()
         FilePath = e.FullPath,
         RetryCount = 0,
         FileName = e.Name
    _memCache.AddOrGetExisting(e.Name, fileData, _cacheItemPolicy);

A simple POCO:

class CacheItemValue
    public string FileName { get; set; }
    public string FilePath { get; set; }
    public int RetryCount { get; set; }

In the constructor, I initialised my cache item policy with a callback to execute when these cached POCOs expire:

_cacheItemPolicy = new CacheItemPolicy
    RemovedCallback = OnRemovedFromCache

The callback itself…

  1. Increments the number retries
  2. Tries and gets a lock on the file
  3. If still locked, put it back into the cache for another 60 seconds (repeat this MaxRetries times)
  4. Else, get on with the intended file operation
private void OnRemovedFromCache(CacheEntryRemovedArguments args)
    // Checking if expired, for a bit of future-proofing
    if (args.RemovedReason != CacheEntryRemovedReason.Expired) return;

    var cacheItemValue = (CacheItemValue)args.CacheItem.Value;
    if (cacheItemValue.RetryCount > MaxRetries) return;

    if (IsFileLocked(cacheItemValue.FilePath))
        _cacheItemPolicy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(CacheTimeSeconds);
        _memCache.Add(cacheItemValue.FileName, cacheItemValue, _cacheItemPolicy); 

     // Now safe to perform the file operation here...

Other Ideas / To Do….

  • Could also store the actual event object
  • Could explore options for non-volatile persistence
  • Might find sliding expiration more appropriate in some scenario


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior)
United Kingdom United Kingdom
Ben is an Expert .NET Software Engineer at the United Kingdom Hydrographic Office. He previously worked for 9 years as a school teacher, teaching programming and Computer Science. He enjoys making complex topics accessible and practical for busy developers.

He works day-to-day with:

SQL Server
JavaScript, jQuery etc…
PowerShell + DSC

Comments and Discussions

QuestionWhy not just use Threads instead? Pin
Alex Schunk3-Jan-18 12:08
MemberAlex Schunk3-Jan-18 12:08 
QuestionGood read Pin
Dankwansere10-Dec-17 16:10
MemberDankwansere10-Dec-17 16:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Technical Blog
Posted 6 Dec 2017

Tagged as


16 bookmarked