FileSystemWatcher to monitor directory size - c#

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;
}

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
}
};

Related

Check the folder if the their is a file zip c# then if exist it will automatically move

Good day,
I have a problem regarding moving the file to other folder.
the scenario is this. Every time i put in the main folder it will automatically copy the file into folder 2.
(TAKE NOTE AUTOMATICALLY CHECK IF THE FOLDER HAS A FILE THEN COPY THE FILE TO FOLDER 2)
this is my code
string[] files = System.IO.Directory.GetFiles(filepath, "*exp.zip", System.IO.SearchOption.TopDirectoryOnly);
if (files.Length < 1)
{
MessageBox.Show("No File");
}
else
{
// COPY THE FILE TO THE OTHER FOLDER
}
THANK YOU GUYS.
I think what you need is an automatic trigger when any zip file is placed in folder than it automatically get copied.
MSDN:
FileSystemWatcher listens to the file system change notifications and
raises events when a directory, or file in a directory, changes.
Check msdn for more detail.
What you need:
FileSystemWatcher fileWatcher;
private void watch()
{
fileWatcher = new FileSystemWatcher();
fileWatcher.Path = path;
fileWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
fileWatcher.Filter = "*.zip";
fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
//Copies file to another directory.
}
It's easy,just need to check for the file extension in the filename :
private void Test()
{
var Folder = "FolderPathHere";
var FilesCount = GetFiles(Folder);
foreach (var file in FilesCount)
{
if (file.Contains("zip"))
{
////ur moving file code here
}
}
}
string fileExtension = "*.zip";//file type
string[] txtFiles = Directory.GetFiles(sourcePath, fileExtension);//find all zip files
foreach (var item in txtFiles)//move all zip files
{
if (File.Exists(item)
{
File.Move(source, destination + item.GetFileName(source));//move the file into destination
}
else
{
File.Move(source, destination2 + item.GetFileName(source));//move the file into destination
}
}

FileSystemWatcher rename Event not firing for subdirectory network path. Except for OnCreated event. It is working properly

My requirement
I am creating one desktop application , I need a network path file information which raname and create ,for that I use FileSystemWatcher
it's provide Created,Renamed,changes and deleted event
My problem
FileSystemWatcher rename event not firing for subdirectory network path,
I already set watcher.IncludeSubdirectories = true, but it not work for rename
public void Setup() {
var watcher = new FileSystemWatcher{
Path = "My network path",
NotifyFilter = NotifyFilters.FileName | NotifyFilters.Attributes | NotifyFilters.LastWrite | NotifyFilters.Security, Filter = "*"
};
watcher.Created += OnCreated;
watcher.Renamed += OnRenamed;
// uncomment out line below to add the error handler
watcher.Error += OnError;
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
}
public static void OnRenamed(object source, RenamedEventArgs e)
{
try
{
MessageBox.Show("Raname call");
}
catch (Exception Ex)
{
errorLog(Ex);
}
}
public static void OnCreated(object source, FileSystemEventArgs e)
{
try
{
MessageBox.Show("OnCreated call");
}
catch (Exception Ex)
{
errorLog(Ex);
}
}

C# Console Application - Inactivity in a folder

I am fairly new to C# coding.. I am trying to setup a code that will alert me when there is an inactivity in a folder. We have a current and archive folder. Once the file is processed in the current folder it will move onto the archive folder.
I have the code to check if there are files in the current folder that's the easy part
DirectoryInfo id = new DirectoryInfo(#"C\");
FileInfo[] TXTFiles = id.GetFiles("*.txt");
if (TXTFiles.Length == 0)
{
Console.WriteLine("Files does not ");
Console.WriteLine("Checking the last processed file in the Archive directory");
Console.Read();
}
if (TXTFiles.Length != 0)
{
Console.WriteLine("Files exists ");
Console.Read();
}
So in the logic where the file does not exist I want to have an additional step to get the timestamp of the last text file that was processed. This is to check for how long there hasnt been any activity .
I am not sure how to proceed. Also instead of writing this information to a console can i send a message to a webservice
Thanks
FileSystemWatcher will be your friend :)
https://msdn.microsoft.com/fr-fr/library/system.io.filesystemwatcher(v=vs.110).aspx
using System;
using System.IO;
using System.Security.Permissions;
public class Watcher
{
public static void Main()
{
Run();
}
[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
public static void Run()
{
string[] args = System.Environment.GetCommandLineArgs();
// If a directory is not specified, exit program.
if(args.Length != 2)
{
// Display the proper way to call the program.
Console.WriteLine("Usage: Watcher.exe (directory)");
return;
}
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[1];
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
// Wait for the user to quit the program.
Console.WriteLine("Press \'q\' to quit the sample.");
while(Console.Read()!='q');
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
}
Source code from MSDN.

C# File and Renaming Automatically from 1?

I wrote this code in c# for change location of folder and all sub-folders of this folder. I want to change name of all folders when copy it to destination. for example I want to change name from 1 to .... . how should I change my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
namespace Folder
{
class clssMoveFolder
{
string temppath;
public string StrtxtSource;
public string destDirName;
public void Directorycopy(string sourceDirName, string destDirName, bool cutSubDirs, string strExtension)
{
try
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
// If the source directory does not exist, throw an exception.
if (!dir.Exists)
{
throw new DirectoryNotFoundException("Source directory does not exist or could not be found: " + sourceDirName);
}
FileInfo[] files = dir.GetFiles();
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
//Get the file contents of the directory to copy.
for (int a = 0; a < files.Length; ++a)
{
// Create the path to the new copy of the file.
if (files[a].Extension == "."+strExtension )
{
temppath = Path.Combine(destDirName, files[a].Name);
files[a].MoveTo(temppath);
}
else if (files[a].Extension == strExtension)
{
temppath = Path.Combine(destDirName, files[a].Name);
files[a].MoveTo(temppath);
}
else if (strExtension == "AllFiles")
{
temppath = Path.Combine(destDirName, files[a].Name);
files[a].MoveTo(temppath);
}
else
files[a].Delete();
dir.Refresh();
}
FileInfo[] filesCheck = dir.GetFiles();
if (dirs.Length == 0 && filesCheck.Length == 0 && dir.Name != StrtxtSource)
{
dir.Delete();
}
// If copySubDirs is true, copy the subdirectories.
if (cutSubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
// Copy the subdirectories.
string temppath= Path.Combine(destDirName, subdir.Name);
Directorycopy(subdir.FullName, temppath,cutSubDirs,strExtension);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
}
}
If you just want to rename a file after copying it you could instead directly copy it under a different name. E.g. instead of copying a.txt and rename it to b.txt afterwards, you could just copy the original a.txt as b.txt to the destination directory.
Renaming can be done by using the File.Move method.
File.Move("a.txt", "b.txt");
If you want to be able to do this even if someone else copies files into a directory (e.g. by using the windows explorer or files written by another application), you may want to take a closer look at the FileSystemWatcher. You can use it to monitor changes in a specified directory (optionally including it's subdirectories) and react on these changes.
...
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"D:\SomeTestDirectory";
watcher.Filter = "*.*";
watcher.NotifyFilter = NotifyFilters.FileName; // Trigger only on events associated with the filename
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true; // Starts the "watching"
...
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Do whatever you want here, e.g. rename the file.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}

How can I watch for newly created files and wait for them to be unlocked?

First the watch method; I need to watch for any newly created jpg files, since I don't know yet the file names. My program creates each time a new jpg in the directory specified by a TextBox. So my first problem is how to know/get the file name when it's being created?
Second problem, how can I use all these methods, the two methods and the event changed (code below)? I have a button click event when I click it, it will create the new jpg file. Then in the button click event I want to start watching it and give a message on a label something like: "Creating file wait", then when the file is created and ready for use "File created".
private void watch()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = SavePathTextBox.Text;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.jpg";
watcher.Changed += watcher_Changed;
watcher.EnableRaisingEvents = true;
}
Then the event watcher_Changed:
void watcher_Changed(object sender, FileSystemEventArgs e)
{
}
And the method that checks if the file is locked or not
public static bool IsFileReady(String sFilename)
{
// If the file can be opened for exclusive access it means that the file
// is no longer locked by another process.
try
{
using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None))
{
if (inputStream.Length > 0)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception)
{
return false;
}
}
This is what i tried:
In the button click event:
private void TakePhotoButton_Click(object sender, EventArgs e)
{
try
{
if ((string)TvCoBox.SelectedItem == "Bulb") CameraHandler.TakePhoto((uint)BulbUpDo.Value);
else CameraHandler.TakePhoto();
watch();
}
catch (Exception ex) { ReportError(ex.Message, false); }
}
In the watch method:
private void watch()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = SavePathTextBox.Text;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.JPG";
watcher.Changed += watcher_Changed;
watcher.EnableRaisingEvents = true;
}
The event watcher_Changed
void watcher_Changed(object sender, FileSystemEventArgs e)
{
if (IsFileReady(e.FullPath) == false)
{
this.Invoke((Action)delegate { label6.Text = "Busy"; });
}
else
{
this.Invoke((Action)delegate { label6.Text = "File Ready"; });
}
}
And the method to find if file is locked or not:
public static bool IsFileReady(String sFilename)
{
// If the file can be opened for exclusive access it means that the file
// is no longer locked by another process.
try
{
using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None))
{
if (inputStream.Length > 0)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception)
{
return false;
}
}
The problem is that sometimes in most of the cases it's getting to the line inside the watcher_Changed event:
this.Invoke((Action)delegate { label6.Text = "File Ready"; });
And making this line twice or somtimes even 3 times in a row.
I can say that each click my camera take one photo and it's creating two files one for example with the name: IMG_0001.CR2 and the Jpg one: IMG_0001.JPG
But i'm not sure if that's why it's getting to the event and doing the line/s there more then once.
I also checked the file in the e.FullPath is always .jpg and never cr2.
The question is why it's getting there more then once and how can i make sure that the file is really ready ? ("File Ready")
Maybe i need somehow to track the file size from 0kb until the size not change any more and then to decide in the event that it's ready or not ?
I see some problems with the way You use watcher.
Watcher should run before You call CameraHandler.TakePhoto or there is a (small) chance You would miss it.
Either do not create new instance of watcher on every TakePhotoButton_Click or stop the old one. Otherwise You would end up with new running watcher with every click and get as many calls to watcher_Changed as many watchers You have.
I have read there is a chance watcher can be garbage collected. I am not sure if it is true, but rather be safe and save it to some local field.
What You are now waiting for is end of writing to some .jpg file. This may do what You need and in that case it is good. But if You want to wait for file create, You need different setting. This worked for me:
string watchDir = Application.StartupPath;
watcher = new FileSystemWatcher(watchDir, "*.jpg");
watcher.NotifyFilter |= NotifyFilters.Size;
watcher.Created += new FileSystemEventHandler(watcher_Created);
watcher.EnableRaisingEvents = true;
protected void watcher_Created(object sender, FileSystemEventArgs e)
{
string changeType = e.ChangeType.ToString();
if (changeType != "Created")
{
return;
}
// file is created, wait for IsFileReady or whatever You need
}

Categories