How to notify the FileSystemWatcher that file copy either from same machine or another machine completes and start processing

123 views Asked by At

I have below program where StartFileWatcher looking into a folder (C:\TEMP) (including subdirectories) and copying all the files info to the C# channel based of file LastWriteTimeUtc and having some logic to compare.

This works most of the case (all the files processing in order by lastwritetime) where copy is immediately completes to the folder C:\TEMP, otherwise order fails.

In my code I am doing some manual adjustment of delay (await Task.Delay(5000, cancellationToken);), if within 5000 ms, the entire copy is done, then processing of files happens in order, otherwise not.

enter image description here

Question is, rather than manual delay adjustments can I notify FileSystemWatcher to start work once copy is completed?

Main:

static async Task Main(string[] args)
{
    string folderPath = @"C:\TEMP";
    CancellationTokenSource cts = new CancellationTokenSource();

    Channel<string> fileChannel = Channel.CreateUnbounded<string>();

    // Start the file watcher
    Task watcherTask = StartFileWatcher(
                folderPath, fileChannel.Writer, cts.Token);

    // Start processing files
    Task processingTask = ProcessFilesAsync(
                fileChannel.Reader, cts.Token);

    // Wait for user input to stop
    Console.WriteLine("Press Enter to stop...");
    Console.ReadLine();

    // Cancel the tasks
    cts.Cancel();

    // Wait for the tasks to complete
    await Task.WhenAll(watcherTask, processingTask);

    Console.WriteLine("Program stopped.");
}

StartFileWatcher:

static async Task StartFileWatcher(
            string folderPath, 
            ChannelWriter<string> channelWriter, 
            CancellationToken cancellationToken)
{
    using (var watcher = new FileSystemWatcher(folderPath))
    {
        List<string> pendingFiles = new List<string>();

        watcher.IncludeSubdirectories = true;
        watcher.Created += (sender, e) =>
        {
            if (!e.Name.StartsWith("~"))
            {
                lock (pendingFiles)
                {
                    pendingFiles.Add(e.FullPath);
                    pendingFiles.Sort((a, b) =>
                        File.GetLastWriteTimeUtc(a)
                                    .CompareTo(File.GetLastWriteTimeUtc(b)));
                }
            }
        };

        watcher.EnableRaisingEvents = true;

        while (!cancellationToken.IsCancellationRequested)
        {
            List<string> filesToProcess;

            lock (pendingFiles)
            {
                filesToProcess = new List<string>(pendingFiles);
                pendingFiles.Clear();
            }

            foreach (var filePath in filesToProcess)
            {
                channelWriter.TryWrite(filePath);
            }

            // Adjust the delay as needed
            await Task.Delay(5000, cancellationToken);
        }
    }
}

ProcessFilesAsync:

static async Task ProcessFilesAsync(
        ChannelReader<string> channelReader, 
        CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            if (await channelReader.WaitToReadAsync(cancellationToken))
            {
                while (channelReader.TryRead(out string filePath))
                {
                    Console.WriteLine($"file: {filePath}," + 
                                      $"LastWriteTime: " +
                                      $"{new FileInfo(filePath).LastWriteTime}");
                    // Simulate processing delay
                    await Task.Delay(2000, cancellationToken);
                }
            }
        }
    }
0

There are 0 answers