I told my FileWatcher, that it should include Subdirectories
_watcher.IncludeSubdirectories = true;
The problem, that I have is, that there are multiple files with the same file-ending.
So my watcher gets triggered multiple times.
I have something like this
(subfolder[x] is the watched one)
mainFolder/subfolder[x]/ -> in this one example.mkv and two other filetypes
mainFolder/subfolder[x]/subfolder2/ -> in this one is just one sample.mkv
FileWatcher is configured to:
_watcher.Filter = "*.mkv";
Currently the "created" event gets triggered two times ("example.mkv" and "sample.mkv")
I would like to have it just triggered once for the "example.mkv" and not for the "sample.mkv".
How can I just "watch" the first subfolder and exclude the second subfolder?
You want to only Watch the target and 1st Order Child Directories/first two levels of the directory tree. Close to 0 code that is able to include subdirectories recusively on a Windows ever had such an ability. It was either "incldue all subdirectories" or "include no subdirectories".
Only code as modern as Robocopy has any ability to define the "depth". And FileWatcher is not nearly that modern. It is (t)rusty like hte Office COM Interop. It is still following the old "all Subdirectories or None" pattern. So you still have to use the old workaround - manual recursion:
Do not use IncludeSubdirectories = true;
Start a normal, non recursive File watcher on the root directory
Itterate over all subdirectories manually. The Directory class should have you covered
Start a seperate, non-recursive watcher for each subdirectory
Unfortuantely FileWatcher is not the most advanced class. For example figuring out wich kind of changed happened is nigh impossible. Wich is why someone took 9 watches with Filters and put them into one class, to get some decent level of information out of this class: https://www.codeproject.com/Articles/58740/FileSystemWatcher-Pure-Chaos-Part-of
Related
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.
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.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How can I watch a file system directory to see when files are added to it?
I am creating a console app in c# which one of its functionality is to scan a fix folder path(example c:\FixedFolderA) say every minute and check if a new folders has been created(Example c:\FixedFolderA\NewFolderB).
So several folders will be created under c:\FixedFolderA.
The new folders will have no subdirectories, just files which I will copy to other locations.
I am not sure of the most efficient design to do this and need your help.
I was thinking of this workflow:
Scan c:\FixedFolderA at the start of the program.
Store all the sub directories in a list.
Create a worker process that scans c:\FixedFolderA and check to see if that sub-directory exists in the list. If the directory doesn't exist perform some action.
My concern is that the umber of sub-directories in c:\FixedFolderA will increase overtime and the program would be traversing all these directories every minute.
Should the routine to check every minute be done with a process?
Can someone please share your ideas with the best design to get me started ?
Thanks .
If you plan to watch a folder for changes, use the FileSystemWatcher class.
Also, if this console application performs a specific task on its own, perhaps it is best to turn it into a Windows Service.
It's almost always better to be notified when an event occurs rather than having to query periodically.
For the context you're describing you can very easily use the FileSystemWatcher class to specify what kind of files you want to be notified about and in which directory you wish to monitor. I put together the following code for you:
FileSystemWatcher fileWatcher = new FileSystemWatcher("C:\\Users\\ByteBlast\\Desktop", "*.*")
{
EnableRaisingEvents = true,
IncludeSubdirectories = true,
NotifyFilter = NotifyFilters.DirectoryName
};
fileWatcher.Created += (sender, eventArgs) => Console.WriteLine("{0} Created", eventArgs.FullPath);
Where I specify the path to my desktop, you will specify for example, C:\FixedFolderA.
You can make sure that you are notified about changes in sub directories by enabling the IncludeSubDirectories property like I did above.
Because you're only interested in folders and not files I set the NotifyFilter property to NotifyFilters.DirectroyName.
Place the code above in your Console Application's void Main() and ensure you stop the console from closing by for example including the following statement beneath the code above Process.GetCurrentProcess().WaitForExit();.
Rather than scanning the directory every minute, you should take a close look at File System Watcher. This will tell you when a change has been made to the directory structure - thus it will be far more efficient. Your program just has to keep track for what changes have been made.
I have an idea for a C# program that works basically like the Windows Explorer. The aim is to display all files and folders, and to show specific information for each of them. One of the features I'm planning is to detect folder sizes which is something the Explorer cannot.
My idea for the algorithm is to cumulate the sizes of all files in the specific folder. However, I'm afraid of performance issues. For example, for displaying the sizes of all folders of C: I have to consider all the files on the whole drive. This will probably take a while and thus the calculation can't be done each time the user switches to a different folder or back.
So I'd like to cache some of the sizes. However, when files change, are added or removed, the cache data becomes outdated. But I do not want to monitor all file changes while the program is not running.
Is there any way I can find out if the cache is up-to-date, e.g. by retrieving some sort of checksum that doesn't require calculating all sizes again? Is there another memory and CPU-efficient way to find out if file sizes have changed since the last calculation? Or is there even another possibility?
Windows Explorer has the Folder size available (# files, size on disk etc) availble for the properties of any disk/folder. Directory Properties Example
As for writing a program, you can certainly use a recurisve DirectoryInfo.EnumerateFiles() to get all the files within a disk/folder.
As for monitoring, you can use the FileSystemWatcher class to monitor changes to any disk/folder.
To keep the cache up to date is going to be difficult because:
Depending on the Partition Formated Type [Fat, Fat32, NTFS, etc] you are limited to what each support.
Any new file (created date > cache date) means you still have to enumerate all the files to filter the list to new files.
Modified files (modified date > cache date) has the same issue.
Unless you use something VERY specific to the Formatted Type beyond what C# provides, updating a cache after the application launch will need to occur every time, and be very intense.
Windows Explorer is a pretty crafty program. It is filled with tricks that are designed to hide the fact that any file system is punishingly slow to iterate. The kind of tricks that I know about:
fake it. Show the folder hierarchy as a treeview and use the [+]
glyph to show that a folder has files or directories inside of it.
Even when it doesn't. That's visible, create an empty directory and
restart your machine. Note the [+] glyph, click it and notice that,
when forced to iterate the sub-directory, it smoothly change the [+]
glyph to a 'nothing there' glyph.
delay it. Harder to see, you need a subdirectory with a lot of
files. Explorer starts a background thread that iterates the
content of the folder. Once it figured it out, it smoothly changes
the status bar text.
tell me what happened. Explorer uses ReadDirectoryChangesW()
heavily. Wrapped in .NET by the FileSystemWatcher class. Key point
is that it gets a notification that something changed in the
subdirectory that the user is looking at. No polling required, that
would have horrible perf. Go back to bullet two.
I have a WinForms app that has a TreeView. The user can drag files from WindowsExplorer to the TreeView, and then they can drag the files back into WindowsExplorer which in affect copies the files to wherever the files were dropped. What I'm trying to do is, if the files already exist in the directory where the files are being dropped, I want to rename the files/folders being copied in ahead of time, so that there's no collision.
Here's how I'm copying files into WindowsExplorer. On the treeView's ItemDrag, I loop through the nodes of the selected node, and then package that into an array. Then, I use this code:
var dataObject = new DataObject(DataFormats.FileDrop, files.ToArray());
dataObject.SetData(DataFormats.StringFormat, dataObject);
DoDragDrop(dataObject, DragDropEffects.Copy);
This works well, but once it ships off to Windows Explorer, it's out of my hands. How can I find out when and where the files are being copied TO and intercept that to make changes? Is this possible?
Explorer Drag & Drop is an excellent article doing what you are trying to achieve.
EDIT2: It seems that there's a C++ article available for the same on CodeProject. But I was unable to find a way of how to do it using C#.
AFAIK, there is no way to know drop target (in your case destination folder). You can look into CFSTR_FILENAMEMAP shell clipboard format, but still in this case you can only provide name mappings before (or in process) of drag-n-drop.
Also note, that default DataObject in .net has limited shell support. So if you need to use mentioned above format, you need to write your own IDataObject implementation (or take someone's implementation, good example with lot shell drag-n-drop related stuff can be found here)
Instead of putting the file names into the dataobject, create a temporary file with a unique/easily distinguishable name and place that file name into the data object's drop list instead (That file could be empty or contain some information you might need). Use a FileSystemWatcher (watching an entire drive) to detect the drop (set the filter to the temporary file name, set IncludeSubDirectories to true, and set Path to root directory of drive to watch.) Initiate the DoDragDrop. Once the unique/easily distinguishable file is dropped, the FileSystemWatcher can tell you where it was dropped and you can do whatever you need to do (e.g. delete the dropped temporary file and replace with the ones you originally wanted to drop. It is a far-from-perfect solution but might help. Better still, it might give someone an idea to come up with a better one!)
One downside is that you don't really know in which drive someone might drop the file and you may have to set up a watcher for several drives. And if you miss a drive (or a network path) then problems .....! Remember to dispose of the watchers after the drop.
There has to be a better way though. e.g. consider when you drag a file from a zip folder. The file is only extracted after the drop.
i don't think that is possible.