Search code examples
c#windows-servicesfilesystemwatcher

FileSystemWatcher to monitor directory size


Hi I am creating a windows service to watch certain directories to see if the size of the directory is reaching its limit. I have created a file system watcher as follows:

            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = dirPaths[i].ToString();
            watcher.NotifyFilter = NotifyFilters.Size;
            watcher.EnableRaisingEvents = true;
            watcher.Changed += new FileSystemEventHandler(OnChanged);

and

 private void OnChanged(object source, FileSystemEventArgs e)
    {
        try
        {
        
        string directory = new DirectoryInfo(e.FullPath).Parent.FullName;//gettting the directory path from the full path

        float dirSize = CalculateFolderSize(directory);

        float limitSize = int.Parse(_config.TargetSize);//getting the limit size 

        if (dirSize > limitSize)
        {
            eventLogCheck.WriteEntry("the following path has crossed the limit " + directory);
            //TODO: mail sending
        }
    }
    catch (Exception ex)
    {
        eventLogCheck.WriteEntry(ex.ToString());
    }

}

CalculateFolderSize checks the size of all the files and subdirectories in the drive.

Now this works fine when I add a file to the directory e.g. a .xls, .txt, etc. file but if I add a folder to the directory it does not trigger the OnChanged event??

if I enable:

watcher.IncludeSubdirectories = true;

it does trigger the Onchanged event but in this case it only checks the subdirectory and not the entire directory.

Please can someone tell me how I can get this to work such that when I copy a folder to the directory being watched it triggers the Onchanged event and calculates the new size of the directory.

my CalculateFolderSize function is as follows if this helps:

//function to calculate the size of the given path
        private float CalculateFolderSize(string folder)
        {
            float folderSize = 0.0f;
            try
            {
                //Checks if the path is valid or not         
                if (!Directory.Exists(folder))
                {
                    return folderSize;
                }
                else
                {
                    try
                    {
                        foreach (string file in Directory.GetFiles(folder))
                        {
                            if (File.Exists(file))
                            {
                                FileInfo finfo = new FileInfo(file);
                                folderSize += finfo.Length;
                            }
                        }
                        foreach (string dir in Directory.GetDirectories(folder))
                        {
                            folderSize += CalculateFolderSize(dir);
                        }
                    }
                    catch (NotSupportedException ex)
                    {
                        eventLogCheck.WriteEntry(ex.ToString());
                    }
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                eventLogCheck.WriteEntry(ex.ToString());
            }
            return folderSize;
        }

Solution

  • You're using the folder path provided by the FileSystemEventArgs so that will be the folder that has changed. Instead, create an object for each directory root that you are monitoring and, inside it, store the root path and use that instead of the EventArgs.

    You may find an easy way to create this object is just to use a lambda function for the event handler as follows. This effectively wraps up the path from the outer scope into a different object for each path you are monitoring.

     FileSystemWatcher watcher = new FileSystemWatcher();
     watcher.Path = dirPaths[i].ToString();
     watcher.NotifyFilter = NotifyFilters.Size;
     watcher.EnableRaisingEvents = true;
     watcher.Changed += delegate (object source, FileSystemEventArgs e)
     {
        float dirSize = CalculateFolderSize(watcher.Path); // using the path from the outer scope
    
        float limitSize = int.Parse(_config.TargetSize);//getting the limit size 
    
        if (dirSize > limitSize)
        {
            eventLogCheck.WriteEntry("the folloing path has crossed the limit " + directory);
            //TODO: mail sending
        }
     };