Mefhisto1
Mefhisto1

Reputation: 2228

Wait until last file is copied with FileSystemWatcher created event

I have a few python unit test files. I'm copying all those files to a directory, which a file system watcher is listening and firing create event. I want to run those tests after all files are copied. The files that are being copied look something like:

unittest1.py

unittest2.py

unittestxyz.py
.
.
.

unittestRunner.py

unittestRunner.py file imports all other unittest files and starts all unit tests as a part of a suite. If I copy files to the watched directory, Created event will fire that many times, in this case 4 times. So, somehow I want to 'wait' until all files are copied and then execute the unittestRunner script. Files are being copied programmatically, and watcher is running as a part of a Windows Service.

I have 2, quite yuck solutions, and they may not even be solutions:

one is to specifically wait for unittestRunner.py to be created:

 watcher.Created += new FileSystemEventHandler((sender, eventArgs) =>
                {
                    if (eventArgs.Name == "unittestRunner.py")
                    {
                      // Run Tests
                    }
                });

but this won't work if runner file gets copied before any other file.

Other is to keep track the number of files that have to be copied somewhere in an xml file, and in the evnet handler check if the current number of copied files are the same:

watcher.Created += new FileSystemEventHandler((sender, eventArgs) =>
                {
                    var totalCount = Directory.GetFiles(testFolder).Length;

                    var doc = new XmlDocument();
                    doc.Load("numberOfFilesToCopy.xml");

                    if (totalCount == doc.GetElementsByTagName("test-files")[0].ChildNodes.Count)
                    {
                        // Number is the same, all files copied, run tests
                    }
                }

Is it somehow possible to wait for all the locks of all the files have been released before starting tests?

Upvotes: 0

Views: 1561

Answers (2)

Fildor
Fildor

Reputation: 16148

In a similar situation, I went this way:

  1. Create a "Lock" File in the target directory. Nothing is startet, as long as this file is present.
  2. Copy all needed files to target directory.
  3. Delete "Lock" File.

The Program reacted on "Deleted" Event of the "Lock" file + Some Delay to ensure all concurrent access will be ended.

I even later on added a second lock file (for the other way), so the target dir won't be copied into while the run of the program was still in progress.

Upvotes: 2

redspidermkv
redspidermkv

Reputation: 551

You can check each file to see if they're accessible. Going from this SO post, you could do the following:

private bool WaitForFile(FileInfo file)
{
    var attemptCount = 0;

    while(true)
    {
        try
        {
            using(file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)) 
            { 
                return true; 
            }
        }
        catch (IOException)
        {
            //File isn't ready yet, so we need to keep on waiting until it is.
        }

        //We'll want to wait a bit between polls, if the file isn't ready.
        attemptCount++;

        if(attemptCount > 5)
        {
            break;
        }

        Thread.Sleep(1000);
    }

    return false;
}

Your idea about using an XML file to keep track of the number of expected files to be copied is also a good one. I recommend you have

var doc = new XmlDocument(); doc.Load("numberOfFilesToCopy.xml");

outside the method though so you don't have to load the same file repeatedly.

Upvotes: 2

Related Questions