Need to copy file after it's creation and changing - c#

I need to copy a file after it's been created and changed twice.
I have no idea how to do it, except by using 3 FileSystemWachers. First one on creation and two for changing.
Is there any easier way?

The FileSystemWatcher has several events that you can use to listen to different types of events on the file system. There is also a NotifyFilter property which you can use to specify which event types it should monitor.
So you don't need to use three different watchers; one would suffice. You just need some form of counter to keep track of how many changes were made to the file. Here's a quick example:
Dictionary<string, int> changeCounter = new Dictionary<string, int>();
...
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"C:\Path\To\Some\Folder";
watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite;
watcher.Created += OnCreated;
watcher.Changed += OnChanged;
...
private void OnCreated(object source, FileSystemEventArgs e)
{
changeCounter.Add(e.FullPath, 0);
}
private void OnChanged(object source, FileSystemEventArgs e)
{
if (changeCounter.ContainsKey(e.FullPath))
{
changeCounter[e.FullPath]++;
if (changeCounter[e.FullPath] == 2)
{
CopyFile(e.FullPath);
}
}
}
This would only call CopyFile after the watcher detected a file creation event and two file change events for a single file. You may also want to modify handle deletions, too, in case you are worried about files being created once, edited, deleted, recreated, and edited—this would trigger CopyFile even though, technically, the file has only been edited once after it was created.

Related

Implementing a command queue in C#

I'm making a backup system and dealing with the fact System.FileWatcher is raising multiple events per change (copying a file raises Created and Changed, for one) by queueing the commands.
Right now, I'm subscribing to events:
watcher.Changed += new FileSystemEventHandler(OnChanged);
and creating an object of a class:
private void OnChanged(object sender, FileSystemEventArgs e)
{
var now = DateTime.Now;
var change = new ChangeCommand(now, _fileLogPath, e.FullPath);
}
ChangeCommand is a class that implements the ICommand interface. My question is how and when to actually enqueue them. Since trying to access a file that is being accessed would throw an exception, I want to keep Peek-ing until it doesn't and then Dequeue.

is there a c# feature to listen to csv file update?

I have a csv file and I would like to make some actions whenever a new row is inserted to this csv file.
is there such a listener in c#?
Thanks a lot
There is a class FileSystemWatcher to inspect the file changes.
FileSystemWatcher MSDN. in your case, you just need to filter with "*.csv".
No, there is not specifically a listener for a row being added, but there is such a thing, in .Net, as a FileSystemWatcher, which is a class that can monitor a file for changes. With it, you can react to a specific set of changes to the file that you choose, but what happens is completely up to you.
You can use the FileSystemWatcher to watch an arbitrary file for change events:
public MainWindow()
{
InitializeComponent();
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Filter = "test1.csv";
fsw.NotifyFilter = NotifyFilters.LastWrite;
fsw.Path = "z:\\temp\\";
fsw.Changed += Fsw_Changed;
fsw.EnableRaisingEvents = true;
}
private void Fsw_Changed(object sender, FileSystemEventArgs e)
{
MessageBox.Show(e.FullPath);
}

FileSystemWatcher Raising Multiple Events

I'm going to start off by apologizing if this is a duplicated question. There were a ton of FileSystemWatcher questions but I didn't see any that addressed my issue.
Ok, so I have a console application in C# that is monitoring a directory, which we will call Root. Root has many subfolders. The purpose of this application is to write to a log file if any .csv files are create, modified, or deleted within Root or any of its subfolders. I currently have this working fine, sort of. The only problem is that when a .csv file is created, modified, or deleted it actually raises the event for all 3.
For example, if I create a file in Root called test.csv, the log file would look like this:
10/04/2012: File F:/Root/test.csv Created
10/04/2012: File F:/Root/test.csv Changed
10/04/2012: File F:/Root/test.csv Created
10/04/2012: File F:/Root/test.csv Deleted
I'm not sure whats going on, so here is the code that sets up the FileSystemWatcher
_watchFolder.Path = ConfigurationManager.AppSettings["RootToWatch"];
_watchFolder.Filter = ConfigurationManager.AppSettings["FileNameToWatch"];
_watchFolder.NotifyFilter = NotifyFilters.FileName
| NotifyFilters.LastWrite;
_watchFolder.IncludeSubdirectories = true;
_watchFolder.Changed += new FileSystemEventHandler(OnChanged);
_watchFolder.Created += new FileSystemEventHandler(OnChanged);
_watchFolder.Deleted += new FileSystemEventHandler(OnChanged);
_watchFolder.Renamed += new RenamedEventHandler(OnRenamed);
try
{
_watchFolder.EnableRaisingEvents = true;
}
catch (ArgumentException ex)
{
AbortMonitoring(ex.Message);
}
And here is my OnChanged event (Renamed is same but has different argument)
protected static void OnChanged(object sender, FileSystemEventArgs e)
{
//compile message to insert into log file.
string message = "File: " + e.FullPath + " " + e.ChangeType;
UpdateLogFile(message);
}
Just add a handler only for the changed event. It should gather all change types. The other types of events like created are there if you want the event to be raised only on a particular change type.
watchFolder.IncludeSubdirectories = true;
_watchFolder.Changed += new FileSystemEventHandler(OnChanged);

Delete/modify a shortcut by targetpath with C#

We have users that rename the shortcut file on their desktop to our application. What is the best way to delete/modify the shortcut based on targetpath if the icon changes for the application? In other words, I'm having a hard time locating the file name because it keeps getting changed.
It's a nice question and I surprised that nobody answered it correctly in 10 years.
The code below iterate through all links in given folder and finds one with TargetPath pointing to the currently executing WinForms app.
Add COM reference to your project to Windows Script Host Object Model.
using IWshRuntimeLibrary;
private static void DeleteShortcuts(string path)
{
// Example for path: Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
foreach (var fileName in Directory.GetFiles(path, "*.lnk"))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(fileName);
if (link.TargetPath == Application.ExecutablePath)
{
System.IO.File.Delete(fileName);
}
}
}
Note: Application.ExecutablePath works for WinForms to get the current exe path, for Console app you should use Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]). Refer to documentation for other types of projects.
You should use FileSystemWatcher class:
Listens to the file system change notifications and raises events when
a directory, or file in a directory, changes.
Infact you can exploit FileSystemWatcher.Changed, FileSystemWatcher.Created, FileSystemWatcher.Renamed , FileSystemWatcher.Deleted events to keep control on your file.
Here is an example by MSDN:
public static void Main()
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "mypath";
/* 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);
}
Renaming a shortcut does not modify the target path, however, the best way I know to work with shortcuts in c# is with the IwshRuntimeLibrary.
To delete a file please use System.IO.File.Delete method
To modify the file you can use System.IO.File.AppendText method
Update after comments from below :
Please use the ShellClass to create or modify shortcuts Also you will
need to get the special directory from desktop using
Environment.SpecialFolder.DesktopDirectory
A very good example showing step by step can be found here http://www.codeproject.com/Articles/146757/Add-Remove-Startup-Folder-Shortcut-to-Your-App

Monitor multiple folders using FileSystemWatcher

Whats the best way to monitor multiple folders (not subdirectories) using FileSystemWatcher in C#?
I don't think FSW supports monitoring multiple folders, so just instantiate one per folder you want to monitor. You can point the event handlers at the same methods, though, which should end up working like I think you want.
The easiest way is to create multiple instances of the FileSystemWatcher object.
http://www.c-sharpcorner.com/UploadFile/mokhtarb2005/FSWatcherMB12052005063103AM/FSWatcherMB.aspx
You'll have to make sure the you handle events between the two folders correctly:
Although some common occurances, such
as copying or moving a file, do not
correspond directly to an event, these
occurances do cause events to be
raised. When you copy a file, the
system raises a Created event in the
directory to which the file was copied
but does not raise any events in the
original directory. When you move a
file, the server raises two events: a
Deleted event in the source directory,
followed by a Created event in the
target directory.
For example, you create two instances
of FileSystemWatcher.
FileSystemWatcher1 is set to watch
"C:\My Documents", and
FileSystemWatcher2 is set to watch
"C:\Your Documents". Now, if you copy
a file from "My Documents" into "Your
Documents", a Created event will be
raised by FileSystemWatcher2, but no
event is raised for
FileSystemWatcher1. Unlike copying,
moving a file or directory would raise
two events. From the previous example,
if you moved a file from "My
Documents" to "Your Documents", a
Created event would be raised by
FileSystemWatcher2 and a Deleted event
would be raised by FileSystemWatcher
Link to FileSystemEventArgs
Out of the box, FileSystemWatcher only supports monitoring a single parent directory. To monitor multiple sibling directories, you would need to create multiple instances of FileSystemWatcher.
You can try cheating this behavior, however, by taking advantage of FileSystemWatcher's ability to include subdirectories. You can create an NTFS junction point (aka symbolic link) as a subdirectory from the directory you are watching. Mark Russinovich of Sysinternals fame has a utility called Junction to simplify creation and management of symlinks.
Note that you can only create symlinks to directories on your local machine.
Although this is an old question I decided to answer, because I couldn't find a good answer anywhere.
So, the aim was to monitor multiple folders (not subdirectories) using FileSystemWatcher? Here's my suggestion:
using System;
using System.IO;
using System.Security.Permissions;
using System.Collections.Generic;
namespace MultiWatcher
// ConsoleApplication, which monitors TXT-files in multiple folders.
// Inspired by:
// http://msdn.microsoft.com/en-us/library/system.io.filesystemeventargs(v=vs.100).aspx
{
public class Watchers
{
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 PATH [...] [PATH]";
return;
}
List<string> list = new List<string>();
for (int i = 1; i < args.Length; i++)
{
list.Add(args[i]);
}
foreach (string my_path in list)
{
Watch(my_path);
}
// Wait for the user to quit the program.
Console.WriteLine("Press \'q\' to quit the sample.");
while (Console.Read() != 'q') ;
}
private static void Watch(string watch_folder)
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = watch_folder;
/* 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;
}
// 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);
}
}
}
Can you simply use multiple instances of the FileSystemWatcher, one for each directory?
You would have to instantiate multiple instances of the FileSystemWatcher object. Though you can bind the Events to the same method and use the sender object to determine which FileSystemWatcher triggered the event.
var fsw1 = new FileSystemWatcher();
var fsw2 = new FileSystemWatcher();
FileSystemEventHandler fsw_changed = delegate(object sender, FileSystemEventArgs e)
{
Console.WriteLine("{0} - {1}", (sender as FileSystemWatcher).Path, e.ChangeType);
};
fsw1.Changed += fsw_changed;
fsw2.Changed += fsw_changed;
or you can pass the paths in-code, to mark a certain range of the domain watched like in this :
multiple monitor link
hope this helps.

Categories