I am using a file watcher. And when a file is created the file watcher should stop until it is called again. I have got the following code which is watching and the loop doesn't stop.
public void startwatch()
{
string path = "C:\\testwatcher\\";
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.EnableRaisingEvents = true;
watcher.IncludeSubdirectories = false;
watcher.Filter = "*.*";
watcher.Created += watcher_Created;
while (true) ;
}
static void watcher_Created(object sender, FileSystemEventArgs e)
{
string FileName = ("C:\\testfilescrated\\");
string text = File.ReadAllText(e.FullPath);
File.WriteAllText(FileName, text);
}
What i want to do is while loop should end when a file is created.
Don't use a busy loop, this will unnecessarily eat CPU. You could use a wait handle, for example using a ManualResetEvent's WaitOne() method:
ManualResetEvent _resetEvent;
public void StartWatch()
{
// Start watching...
// Wait until signaled.
_resetEvent = new ManualResetEvent(false);
_resetEvent.WaitOne();
}
void watcher_Created(object sender, FileSystemEventArgs e)
{
// Handle your file...
// And signal.
_resetEvent.Set();
}
Related
Each time a file is changed some forms need to be created but the FileSystemWatcher_Changed method only works once and I don't know why.
First time a txt is changed it work correctly but if i make a second change the FileSystemWatcher_Changed method is not called again.
private void button1_Click(object sender, EventArgs e)
{
RunFileSystemWatcher();
}
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public void RunFileSystemWatcher()
{
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = "C:/";
fsw.NotifyFilter = NotifyFilters.LastAccess;
fsw.NotifyFilter = NotifyFilters.LastWrite;
//fsw.Created += FileSystemWatcher_Created;
fsw.Changed += FileSystemWatcher_Changed;
fsw.Filter = "*.txt";
fsw.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// ThreadStart delegado = new ThreadStart(showForms);
Thread hilo = new Thread(()=> showForms(e));
hilo.Start();
}
private void showForms(FileSystemEventArgs e)
{ //leer fichero
foreach (DataRow dr in r.asientosByTxt(e.FullPath).Rows)
{
//MessageBox.Show(dr[1].ToString());
Thread hilo2 = new Thread(() => Formsss(new Form2());
hilo2.Start();
}
}
private void Formsss(Form2 jugador)
{
Application.Run(jugador);
}
I am very new to coding and I'm writing an application which will rename files
by appending milliseconds to the existing filename of files which have been scanned in from an MFD.
The folder is a shared folder and the renamed file should stay within it and not be copied elsewhere.
From doing a lot of searching, I know that File.Move is my way forward, however, I can't seem to get it to work.
Here's my code:
private void MonitorToggle_Click(object sender, EventArgs e)
{
// Create a new FileSystemWatcher object.
FileSystemWatcher fsWatcher = new FileSystemWatcher();
switch (MonitorToggle.Text)
{
// Start Monitoring…
case startMonitoring:
if (!FilePathField.Text.Equals(String.Empty))
{
//Set the watched folder path equal to the file path variable
fsWatcher.Path = FilePathField.Text;
// Set Filter.
fsWatcher.Filter = (FileTypeField.Text.Equals(String.Empty))? "*.*" : FileTypeField.Text;
// Monitor files and subdirectories.
fsWatcher.IncludeSubdirectories = true;
// Monitor all changes specified in the NotifyFilters.
fsWatcher.NotifyFilter = NotifyFilters.LastWrite;
fsWatcher.EnableRaisingEvents = true;
// Raise Event handlers.
fsWatcher.Changed += new FileSystemEventHandler(OnChanged);
fsWatcher.Created += new FileSystemEventHandler(OnCreated);
}
else
{
MessageBox.Show("Please select a folder to monitor.", "Warning",MessageBoxButtons.OK, MessageBoxIcon.Warning );
}
break;
// Stop Monitoring…
case stopMonitoring:
default:
fsWatcher.EnableRaisingEvents = false;
fsWatcher = null;
break;
}
}
public void OnChanged (object sender, FileSystemEventArgs e)
{
FileInfo file = new FileInfo(e.Name);
string dateStamp = DateTime.Now.ToString("fff");
string fName = file.Name;
string newFile = string.Concat(fName, dateStamp);
File.Move(fName,newFile);
}
public void OnCreated(object sender, FileSystemEventArgs e)
{
FileInfo file = new FileInfo(e.Name);
string dateStamp = DateTime.Now.ToString("fff");
string fName = file.Name;
string newFile = string.Concat(fName, dateStamp);
File.Move(fName, newFile);
}
private void BrowseButton_Click(object sender, EventArgs e)
{
// Create FolderBrowserDialog object.
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
// Show a button to create a new folder.
folderBrowserDialog.ShowNewFolderButton = true;
DialogResult dialogResult = folderBrowserDialog.ShowDialog();
// Get selected path from FolderBrowserDialog control.
if (dialogResult == DialogResult.OK)
{
FilePathField.Text = folderBrowserDialog.SelectedPath;
Environment.SpecialFolder root = folderBrowserDialog.RootFolder;
}
}
Whenever I create a new file in the folder I'm watching, it does absolutely nothing. At first I thought it may be because I only had the "OnCreated" method, so I then copied it into the "OnChanged" method (I wasn't sure if copying an existing file into the folder counted as it being "created" but I've had no luck).
Out of interest, I'm also getting an exception thrown if I don't specify a type in the filter, but that's much less pressing at the minute.
If anyone can offer any pointers of where I may be going wrong, it'd be greatly appreciated.
There are a few problems with your code.
First, you should use e.FullPath instead of e.Name, otherwise the code will try to rename the file in the current directory, instead of watched directory.
Second, to receive Created event you should include NotifyFilters.FileName.
However, this will not help you much, because the file is locked in the created and changed events until the file is copied, so you'll get an exception. Also, you'll probably receive more than one Changed event (in my tests I always receive two, regardless of the file size, but it may be different on the different versions of Windows or .Net framework).
To fix this, you may use timers or threads to accomplish the task. Here's an example using ThreadPool thread. Whenever created is fired, you create a new thread. In the thread you check whether a file is locked (trying to open file), and when the file is unlocked, do the rename.
public class FileMon
{
public static void Run()
{
FileSystemWatcher fsWatcher = new FileSystemWatcher();
fsWatcher.Path = #"C:\Test\";
fsWatcher.Filter = "*.*" ;
fsWatcher.IncludeSubdirectories = true;
// Monitor all changes specified in the NotifyFilters.
fsWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName ;
fsWatcher.EnableRaisingEvents = true;
// Raise Event handlers.
fsWatcher.Changed += OnChanged;
fsWatcher.Created += OnCreated;
Console.WriteLine("[Enter] to end"); Console.ReadLine();
fsWatcher.EnableRaisingEvents = false;
}
static void Worker(object state)
{
FileSystemEventArgs fsArgs = state as FileSystemEventArgs;
bool done = false;
FileInfo fi = new FileInfo(fsArgs.FullPath);
do
{
try
{
using (File.Open(fsArgs.FullPath, FileMode.Open))
{
done = true;
}
}
catch
{
done = false;
}
Thread.Sleep(1000);
} while (!done);
Console.WriteLine("DOne");
string dateStamp = DateTime.Now.ToString("fff");
string fName = fi.FullName;
string newFile = fsArgs.FullPath + dateStamp;
File.Move(fsArgs.FullPath, newFile);
}
private static void OnCreated(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"Created {e.ChangeType} : {e.Name}");
ThreadPool.QueueUserWorkItem(Worker, e);
}
static void OnChanged(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"{e.ChangeType} : {e.FullPath}");
}
}
My FileSystemWatcher isn't throwing any events. I've looked at these similar questions, none seem to be an answer for my problem:
*Edit: My goal is to capture when an XLS file is copied to or created in a directory.
Filesystemwatcher doesn't trigger event
FileSystemWatcher - event not firing the second time
FileSystemWatcher Changed event doesn't fire
FileSystemWatcher - only the change event once firing once?
Monitor class:
public class Monitor
{
FileSystemWatcher watcher = new FileSystemWatcher();
readonly string bookedPath = #"\\SomeServer\SomeFolder\";
public delegate void FileDroppedEvent(string FullPath);
public event FileDroppedEvent FileDropped;
public delegate void ErrorEvent(Exception ex);
public event ErrorEvent Error;
public Monitor()
{
watcher.Path = bookedPath;
watcher.Filter = "*.xls";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
watcher.Error += new ErrorEventHandler(watcher_Error);
}
void watcher_Error(object sender, ErrorEventArgs e)
{
Error(e.GetException());
}
void watcher_Changed(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Created) return;
FileDropped(e.FullPath);
}
public void Start()
{
watcher.EnableRaisingEvents = true;
}
public void Stop()
{
watcher.EnableRaisingEvents = false;
}
}
Simple form with Listbox:
public partial class Form1 : Form
{
Monitor monitor = new Monitor();
public Form1()
{
InitializeComponent();
FormClosing += new FormClosingEventHandler(Form1_FormClosing);
Load += new EventHandler(Form1_Load);
monitor.FileDropped += new Monitor.FileDroppedEvent(monitor_FileDropped);
monitor.Error += new Monitor.ErrorEvent(monitor_Error);
}
void Form1_Load(object sender, EventArgs e)
{
monitor.Start();
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
monitor.Stop();
}
void monitor_Error(Exception ex)
{
listBox1.Items.Add(ex.Message);
}
void monitor_FileDropped(string FullPath)
{
listBox1.Items.Add(FullPath);
}
}
What am I doing wrong?
Try this out. Works for me for a very similar task.
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Created += new FileSystemEventHandler(handler);
watcher.Renamed += new RenamedEventHandler(handler);
This may be because the file metadata hasn't been updated yet. This may happen if you are continuously writing to the file.
Have you tried the following:
watcher.Path = directory name;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.xls";
watcher.Changed += OnDirectoryChange;
watcher.Error += OnError;
watcher.EnableRaisingEvents = true;
// Watch only files not subdirectories.
watcher.IncludeSubdirectories = false;
Your issue is with the filters as well as your events I believe. NotifyFilters.LastAccess will only trigger when a file is opened. Try using:
NotifyFilters.LastWrite | NotifyFilters.CreationTime
This will watch for written/created files. Next, hook up to the Created delegate to handle newly created files:
watcher.Created += YourDelegateToHandleCreatedFiles
The way FileSystemWatcher works is to first use the NotifyFilters to limit the event triggers. Then, you use the actual events to do the work. By hooking into the Created event you'll only do work when a file is created.
This is mt first time trying to write a not web based program, and my first time writing anything in C#.
I need a program that monitors folders, but I can't get it to work.
I have used the example from this post Using FileSystemWatcher with multiple files but is trying to make it a form.
My current problem comes in the ProcessQueue function where fileList apparently is defined in another thread.
Whenever a file is actually submitted to the watched folder I get an error that using fileList is a cross thread call
Can anyone explain this error to me, and how to fix it?
namespace matasWatch
{
public partial class Form1 : Form
{
private int n = 1;
private bool isWatching = false;
private List<string> filePaths;
private System.Timers.Timer processTimer;
private string watchedPath;
private FileSystemWatcher watcher;
public Form1()
{
filePaths = new List<string>();
watchedPath = "C:\\Users\\username\\Desktop\\test";
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (!isWatching)
{
button1.Text = "Stop";
isWatching = true;
watcher = new FileSystemWatcher();
watcher.Filter = "*.*";
watcher.Created += Watcher_FileCreated;
watcher.Error += Watcher_Error;
watcher.Path = watchedPath;
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
}
else {
button1.Text = "Watch";
isWatching = false;
watcher.EnableRaisingEvents = false;
watcher.Dispose();
watcher = null;
}
}
private void Watcher_Error(object sender, ErrorEventArgs e)
{
// Watcher crashed. Re-init.
isWatching = false;
button1_Click(sender, e);
}
private void Watcher_FileCreated(object sender, FileSystemEventArgs e)
{
filePaths.Add(e.FullPath);
if (processTimer == null)
{
// First file, start timer.
processTimer = new System.Timers.Timer(2000);
processTimer.Elapsed += ProcessQueue;
processTimer.Start();
}
else{
// Subsequent file, reset timer.
processTimer.Stop();
processTimer.Start();
}
}
private void ProcessQueue(object sender, ElapsedEventArgs args)
{
try
{
fileList.BeginUpdate();
foreach (string filePath in filePaths)
{
fileList.Items.Add("Blaa");
}
fileList.EndUpdate();
filePaths.Clear();
}
finally
{
if (processTimer != null)
{
processTimer.Stop();
processTimer.Dispose();
processTimer = null;
}
}
}
}
}
I assume that fileList is a windows forms control. The ProcessQueue method is called from a timer thread which is by default a background thread. The fileList control resides in the UI thread. You need to use the Invoke() method of the form passing it in a delegate the updates the fileList control.
Invoke(new Action(() =>
{
fileList.BeginUpdate();
foreach (string filePath in filePaths)
{
fileList.Items.Add("Blaa");
}
fileList.EndUpdate();
filePaths.Clear();
}));
Try using System.Windows.Forms.Timer instead of System.Timers.Timer so the timer tick event is executed on the UI thread.
See here for more details.
So, I'm trying to make a file changed notifier, and I need to make it so the text in a textbox updates whenever the contents of the file are changed. This is what I have so far:
string path = "C:/Users/Max/Dropbox/Public/IM.txt";
StringBuilder b = new StringBuilder();
private void Window_Loaded(object sender, EventArgs e)
{
TB.Text = File.ReadAllText(path);
b.Append(TB.Text);
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path.Remove(path.Length - 6, 6);
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.txt";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
TB.SelectionStart = TB.Text.Length;
TB.ScrollToCaret();
}
private void OnChanged(object source, FileSystemEventArgs e)
{
TB.Text = File.ReadAllText(path);
}
This seems to raise the event correctly, but as soon as it touches the code in the OnChanged event, the program exits, no errors or anything, just closes. I have tried to stop it from closing, I have even tried putting e.Cancel under the formclosing event, but nothing seems to work. Any ideas? I can provide more info if needed.
Have you tried wrapping the code in try catch
private void OnChanged(object source, FileSystemEventArgs e)
{
try
{
TB.Text = File.ReadAllText(path);
}catch(Exception e)
{
//Show exception in messagebox or log to file.
}
}
Try this in your Changed method
if (TB.InvokeRequired)
{
TB.Invoke(new MethodInvoker(delegate { TB.Text = File.ReadAllText(path); }));
}