Why do I not get notice that files are renamed from FileSystemWatcher - c#

I have some code that watches the file system for changes and updates a container of file representations. All works for the most part, until you rename a directory. I would expect to get a rename event for all the files and subfolders of the renamed directory since they have new paths, but I only get a single message that the parent directory has changed names. Is there an event i've forgotten, or a flag that needs set? Currently I'm handling the directory rename and iterating through my collection to update the files to the new name, but I feel like there should be something in place to receive a notification for each file instead.
My setup:
FileSystemWatcher watcher = new FileSystemWatcher(item.Path);
watcher.EnableRaisingEvents = true;
watcher.Created += new System.IO.FileSystemEventHandler(OnMediaCreated);
watcher.Deleted += new System.IO.FileSystemEventHandler(OnMediaDeleted);
watcher.Changed += new System.IO.FileSystemEventHandler(OnMediaChanged);
watcher.Renamed += new System.IO.RenamedEventHandler(OnMediaRenamed);

I don't think one usually consider the contained files to be changing if the container changes it's name. Which would be why you don't get an event for the contained files.
May I suggest that you create a double-linked tree-representation of the directory structure, so that each file and directory knows of the container it is in. Then make a ToString() override in the file representation that traverses your tree to the root to build the display-string.
When you get your directory rename event you can find the directory in your representation and trigger an update for each of the files leafing out from this branch.
That way you won't have to loop through things, but rather use recursion, if that seems more elegant to you.
Also, note that FileSystemWatcher has a buffer overflow issue you might wanna check out so you don't loose events.

Ok, for a start, please use consistent terminology within the post. You've mentioned directory, folder, and file almost interchangeably. For the sake of discussion I'll drop this down to folders and files. From what you describe you are watching a folder which contains files and possibly sub-folders. You rename the folder, and you are expecting media renamed events for all of the files (and sub-folders if applicable) to be raised as well? No, I don't believe you will get them.
The FileSystemWatcher hooks in to watch the contents of a folder, not the folder itself. You can verify this behaviour by hooking to a folder and renaming the folder then renaming an item within the folder. (and displaying the full path of the change) you will notice that the path of the renamed item retains the original folder name. Renaming the folder does not invalidate the watcher, but it doesn't catch the event either. However, if you have a sub-folder under the watched folder, with a file under it, and rename the sub-folder and it's child file, the full path of the child will reflect it's parent folder's name change. Kind of hard to describe but: (IncludeSubdirectories = true)
Folder1 (watched)
File1
Folder2
File2
Renaming Folder 1 then file 1. Folder1's name change is not detected, and no, file 1 won't fire a change either. It's name didn't change. Renaming File1 after Folder1's name change will still show "Folder1" as the path.
Renaming Folder2 will be detected and report back the new name. renaming File2 after Folder2 was renamed will be detected and File2's full path will show the updated Folder2 folder name.
If you want to detect renames to the watched directory then what you actually need to do is watch the directory level above it with a Filter set to the directory you're actually interested in. Either use one FSW with IncludeSubdirectories, or two filesystem watcher, one watching the folder, and another for it's contents. When the folder change is detected, update your external references with the folder name change as necessary, then re-initialize the content watcher one so that path names are returned correctly.

You need to enable your FileSystemWatcher object to Include subdirectories.
watcher.IncludeSubdirectories = true;

Related

Moving and cut folders INSIDE watched folder C#

I am using a FileSystemWatcher and i got 2 cases that don't raise events.
lets say i watch on C:/temp,
In case i have already 2 folders with files inside the watched directory, if i cut-paste or move them inside the watched dir to another folder i dont get any event.
Some one know a way i can get events on this files that moved?
Watched directory:
c:/temp
|--test1
| |--test1.txt
|
|--test2
| |--test2.txt
if i move or cut-paste test2 folder into test1 i don't get event on test2.txt.
EDIT: I'm using the code from FileSystemWatcher docs which can find here:
https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?view=net-5.0
hope you can help me, thanks :)
Moving a folder or a file doesn't change it. If you want to track moves, make sure to watch for the Renamed event and set the filters appropriately.
As per the documentation:
COPYING AND MOVING FOLDERS
Event Handler
Events Handled
Performs
OnChanged
Changed, Created, Deleted
Report changes in file attributes, created files, and deleted files
OnRenamed
Renamed
List the old and new paths of renamed files and folders, expanding recursively if needed.
Note that strictly speaking, the file system watcher doesn't watch for changes in content - only the filesystem entries. It's possible to change file contents without changing the filesystem entries, so make sure that it's good enough for your use.

How to ignore a file while using FileSystemWatcher and the events it triggers from modifying/changing the folder it's in?

I'm trying to use the FileSystemWatcher to watch a specific subdirectory and log the events to a file. I can ignore the file changes but I can't get around ignoring the changes notified by the folder it is in. So I get stuck in an infinite loop of the folder it's in being changed, logged to the file, the folder is changed, the changed it logged, etc. Is there a way to stop this without completely ignoring the folder the file is in? I can't differentiate between a change made to the folder from a different file or the file used for logging changes. For example, if I have a folder named "Stuff" and the files "log.txt" and "work.txt", if I modify "work.txt" then I will get a notification that "work.txt" changed, and "Stuff" changed, and "log.txt" which will then modify "Stuff" which will be logged etc.

FileSystemWatcher Filter - Detect Zipped Files?

I'm using a FileSystemWatcher to detect that a text file is created in directory A and subsequently created in directory B.
The issue I'm having is, the process which moves the file from directory A to directory B also zips the file up, changing the filename from say "999_XXX_001.txt" to "999_XXX_001.txt.zip"
Three problems with this;
1) I can no longer open and read the file to analyse the contents
2) The filename has changed
3) The FileSystemWatcher appears to only support a single extension
Solution
Using two watchers, one for ".zip" and one for ".txt", I'm removing the .zip and comparing filenames because moved files no longer exist to be compared byte-for-byte.. I guess the real question here was how can I use the watcher to detect ".txt.zip" as an extension!
Why? You would have to wait until the process has finished its zipping magic and afterwards you can open the zip file with your framework of choice
Why is it a problem itself that the filename has changed?
No, the file watcher will detect any change of all files within the given directory
But maybe it is better to describe what you actually try to achieve here. There is probably a better solution to what you actually need.

How to save a file's original location?

This is what i'm trying to do in my application:
On startup, the application searches for specific files (*.txt for example) in a specific folder (let's say c:\testfolder + all subfolders) and stores their path in a simple string[]. Some files might be located in the root-folder (c:\testfolder), some files have additional subfolders (c:\testfolder\subfolderA\subfolderB).
Now, when I click on a button, all selected files are moved to a temp-folder (like c:\testfolder\temp). When I now close and reopen the application, I want to move all files from the temp-folder to their original location. Obviously this won't work, since the original path was overwritten after restarting the app.
This might be an easy task, but could someone maybe give me hint on how I could do this?
/edit
Would it be possible to ignore a specific folder (temp-folder in this case) when searching for files? Basically moved files are ignored & the old path is still saved (in Properties.Settings. for example) from the first start.
Current code I'm using to get all files:
var files = Directory.EnumerateFiles(file_path, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".jpg") || s.EndsWith(".png"));

Detect and Log copy/paste/delete/cut operations in File Explorer

I want to detect and log to file Explorer operations such as copy/cut/delete/paste.
I have read about FileSystemWatcher, but I also noticed it has some issues since there is no copy/cut events available which can be confusing with whatever I want to do.
The operating system and FileSystemWatcher object interpret a cut-and-paste action or a move action as a rename action for a folder and its contents. If you cut and paste a folder with files into a folder being watched, the FileSystemWatcher object reports only the folder as new, but not its contents because they are essentially only renamed.
FileSystemWatcher is hooking the create file and delete file events to the changed and renamed events which can't really help me to determine if it was made by the user or some another process. Furthermore I cannot be 100% sure what happened to the file whether it was copied or cut etc.
I also need to keep track of the locations "from/to" and the name of file.
Is there some alternative to the FileSystemWatcher that can distinguish between these actions?
I think the FileSystemWatcher would be of use in this scenario. You could use the Changed event, which occurs when a file or directory is changed - like a copy/paste action.
See the MSDN Documentation for this event, and the class itself. Note that there are other events that you can also use for the delete/cut actions.
The events use the FileSystemEventArgs which contains properties for FullPath and Name.

Categories