FileSystemWatcher

bpayne111

Well-known member
Joined
Feb 28, 2003
Messages
326
Location
BFE
first off heres the code
C#:
#region Declarations
		FileSystemWatcher _watcher = new FileSystemWatcher("C:\\" ,"*.pgn");

		#endregion
		
		private void frmMain_Load(object sender, System.EventArgs e)
		{
		_watcher.IncludeSubdirectories = true;
		_watcher.EnableRaisingEvents = true;
					
		}

		private void _watcher_Created(object sender, System.IO.FileSystemEventArgs e)
		{ 
			StreamReader sr;
			StreamWriter sw;
			try
			{
				sr = new StreamReader(e.FullPath);
				sw = new StreamWriter("AutoCompiledChessGames",true);
				
				while (sr.Peek() != -1)
				{
					sw.WriteLine(sr.ReadLine());
				}
				sr.Close();
				sw.Close();

			}
			catch (Exception err)
			{
				MessageBox.Show(err.Message);
			}

		}

When this code is run and a .pgn file is created the _watcher_Created event fires twice (thats expected)
i can get around that fairly easily...
my problem though is that i get different exceptions thrown when i run this method.
Sometimes i will get "FileNotFoundException"
and sometimes i will get "This file is in use by another program"
(Note a step through in the debugger works though; although it does call the event twice so my file is written twice.)

it seems as if with the FileNotFoundException that the watcher is doing its job so well that the file isnt actually created yet when the event fires.

The second seems to be that the file is in the process of being written to so therefore cannot be accessed.

My question is... How can i ensure that the file is ready to be read by my program. So that i can write its data to my file.

Is there a method that checks for a files status?

looks like im hitting the books on this one
i hope someone has some info for me

thanks
brandon
 
Code:
using System;
using System.Threading;
using System.IO;

namespace ConsoleApplication1
{
	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	class Class1
	{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			string filename = @"C:\somefile.tmp";
			//see if the file can be read, if not, sleep the thread for 30 sec.
			while(!CanReadFile(filename))
				Thread.Sleep(30000);
			//open the file 2 read
			TextReader text = File.OpenText(filename);
		
			//open the file 2 write
			StreamWriter sw = new StreamWriter("AutoCompiledChessGames.mcg", true);
			//write all the lines in readFile
			sw.Write(text.ReadToEnd());
			//flush the buffer, always important when writing.
			sw.Flush();

			//close the streams
			sw.Close();			
			text.Close();
		}

		/// <summary>
		/// Determines if a <see cref="FileStream"/> can be created with read-only access.
		/// </summary>
		/// <param name="filename">The path of the filename to open.</param>
		/// <returns>true if a read-only <see cref="FileStream"/> can be created using the specified filename.</returns>
		/// <remarks><see cref="FileStream.Close"/> can throw an <see cref="IOException"/>. This exception
		/// will be caught but not handled and the <see cref="FileStream"/>.</remarks>
		static bool CanReadFile(string filename)
		{
			try
			{
				File.OpenRead(filename).Close();
			}
			catch
			{
				return false;
			}
			return true;
		}
	}
}

If the remarks for CanReadFile bother, it can be easily modified so Close() will throw an exception and let the caller deal w/ it.
 
well what i found was that a change event occurs as well and calling my method during the change even worked fine.
It turns out nullifying the double call to the Created and Changed method is harder than i thought...
ive considered some ways of dealing with it but all have a bug somewhere... is there a fool proof way of canceling the extra create and changed events?

id like to learn the basics of threading... where should i start?
thanks for the code that alone teaches me some about threading

brandon
 
The final goal is to have the FileSystemWatcher find new chess games and from its methods add those games to a database (for now a text file is my temporary database).
When a new chess game created... the created and changed events are both called twice... id like to stop that or at least make sure that im not being redundant with my file access.

thanks
brandon
 
I think the only event you need to listen for is the FileSystemWatcher.Created event. If that event is still being raised twice for the same file, youll need to work around that.

I option is to maybe use an Array to store ackonwledged created file paths so that way when the Created event gets raised, youll know if its a dupe event. When your done processing the file, just remove the file path from the Array.

There are other ways though, depends on what you plan to do with the file in the future.

Ive only used the FileSystemWatcher in a project once. FOrtunately, Ive didnt have the Created event raised multiple times for the same file. The docs state that this can happen though. I was using it on win2k server.
 
yes ive considered many ways of nullifying the extra event. The problem is i can not simply just use a string to see if its the same file being used each time because the file might be edited twice in a row legitimatly.
ive considered using the filename and the LastAccessTime or LastWriteTime property of a file. but even then im assuming that a file is never accessed or written too twice in the same minute. Thats as fool proof as i can think to get it.

There is a thing called Lightning chess and it is quite popular among players. Lightning chess games are usually less than 2 minutes long. Making it very possible to lose in less than a minute.
If a game like that was played immediatly after any other game and the program being used Appended a file each time a game was completed. Then the game would not be recorded.

My third idea to help kill that bug was to use the size of a file as a determining factor. The problem is i cant find a way to determine the file size (im embarassed to say that one).

The only assumption with that idea is. A user edited the file manually, saved it, immeditatly saw the mistake and corrects it in a way that the file size does not change.
If that situation happens in less than a minute once again the edit is missed.
So ill need a third stipulation to completly verify everything... but now im out of ideas besides completly checking every line of the file. Which is a very bad idea in this case because files can contain thousands of chess games at once.

In case youve forgotten the Questions are HOW DO I RETRIVE THE FILE SIZE?
WHAT ELSE CAN I CHECK TO MAKE IT FOOL PROOF?

Whats a chess nerd to do?
brandon


sorry its so long of a post... just decided to break down whats going on to the fullest
 
ohh i thought that was the length of the filename whoops...
can you think of any other ideas that would make this work flawless?
 
I would still use the array, just manage it differently like, maybe just have the filepath added to the array (allow duplicate filepaths in the array) when events get raised and have a seperate thread process the files in the array. or maybe, when adding a filepath to the array, if the filepath already exists, remove it from the array and add the removed filepath to the end of the array.
 
thats my whole issue... reduce redundancy while keeping
accuracy

files can be thousands of lines if i check it twice i would be wasting a lot of time and resources

can i implement the checksum of a file to see if it has changed from the last time it was caught by filesystemwatcher?

i never thought this would be so difficult

thanks for the help
brandon
 
Dont allow duplicate filepaths in the array. Problem solved!


Well, when I think about it later... not really. give me a few min
 
Last edited by a moderator:
problem not solved.. because if the same file is edited twice in a row it will be ignored...

nice try though
thanks
brandon
 
Tell me this. The created event gets raised
What methods listen on this event, and what do they do?

My guess is you have aMethod Foo that
1) Open the created file
2) read some data from the file
3) close the file
4) write some data to a db


What is the file format for the chess games?
Can you get all of the chess games in a file?

Im still trying to think of a way to handle this properly

Also, what does the created event signify? That a game has been added to the file?
 
ok the created event is called, but sometimes is not ready to be read. Then another created event is called for the same file.
The changed event is called, and the file is ready for access.
The changed event is called again for the same file.
.pgn files are chess game files. They can hold as many chess games as a file can be large.
As of now im not writing to a db because i know just enough to piss me off about them. So im writing them to another text file instead. My text file i created in my program will contain all games from all files. Which will eventually actually be a db which gathers statistics about these games.
I think file.Length will be enough to satisfy my users.
it is very rare a person would go into a pgn file and edit it. the only reason would be if they are playing the game blind (without a board) or if a certain website they play at has some bugs in the way they notate a chess game in the pgn file.
Both of these occurances are fairly rare, but they can happen so therefore as a programmer i feel obligated to do something to fix that.

so one day i may think of a solution but who knows
im curious of the CheckSum of a file. I know antivirus software uses this to determine if the file has been edited or something.
know anything about CheckSum?
i may start anoher post with that question
 
yes ive been over that idea before... basically it = the same two problems that i ahve alraedy..
hmmm well you know a new thought just occured (amazing considering ive been drinking)
If i am allowed to assume that the created and changed events are called twice everytime for a file then i could do that.
Well after mental analysis that creates a new problem. (assuming antivirus causes these events) I can not assume everyone has an antivirus that would fire these events twice.
So this is leading me in a new direction that might help though...
If all antivirus programs cause these events to fire like they do. I could check to see if antivirus software is enabled when the program starts. The more i think about this th emore problems it creates than solutions because more and more things could go wrong with this (lets say for some odd reason they disable the antivirus or something)
So this leads me to my newest idea to solve this.
If and only if all antivirus programs cause these events to fire again (and it only happens once no matter how many antivirus programs are running) Then i could try somehow to see if antivirus is enabled on that computer and THEN i could easily cancel out the extra event with a counter. This would force me to check for the change of status of antivirus software all the time with another thread which im not happy with but able to accept.
So where do i go with that idea? i almsot thin ki should start another post for that. but id like to see this one get over 100 reads.
It looks like we are breaking new ground thanks for your input once again. I hope this post of mine makes sense cuz i did have like 6 beers so im likely to have made some typos so bare with me.
thanks again
brandon
 
ArrayList that stores Filename and filesize
Im not sure if CRC will work because I dont know where the file info (last created, last accessed, last written to, date created, etc) is stored. If somehow that info is also used in creating the CRC, you will probably get a unique CRC for each event raised on that file (assuming once the file is created the antivirus is going to access the file and do stuff). So I would try an array list that stores the filelength and the filesize.
 
Back
Top