Click here to Skip to main content
Click here to Skip to main content

Status Reporter using text file and fileSystemWatcher

, 18 Oct 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Tool to report another programs buffer of messages sent to a text file

Introduction

This program was written to allow easy progress or status reporting of another programs activities.
It operates on the premis that the program being monitored will write numbered status messages to a text file.
It uses a FileSystemWatcher to detect changes in the file, and reads the messages and displays them in a dialog. I first tried the program where the main program would just write one message at a time to the message text file. I quickly found that was fragile as really fast operations could not be written fast enough to the file. So I tried having the main program keep a list of the last 20 messages, and try writing to file each time
a new message was generated. If a few writes failed, it is no problem as the next ones will have the messages that got missed. The watcher program reads the file each time it changes, and filters out past messages by their number, then displays the new ones. The reporting dialog closes after a time delay, or if the message text file is deleted. Those details are what makes this tool a bit more valuable. It allows you to take a program written in any other language, maybe one that does not easily support multi-threading, and dependably see a progress report of some activity.

Background

I wrote this to help with programs written for Autodesk's AutoCad program. Tools that displayed progress bars well on windows XP, acted differently on Windows 7, so I had to do something to deal with the UI "blocking" going on for long processes. The AutoCad tools are written in AutoLisp, and I specifically wanted an external process doing the reporting, so no chance of blocking whatsoever.

Using the code

To use the status watcher, you will run the StatusByFileWatch.exe as an external process. It takes two command line arguments, in this order:

  • the full text file filename
  • the delay in microseconds, for the dilaog to close on its own when no activity happens

The Demo program is written in C# but the principles here apply to any language. In any program that needs its messages to be watched, set up variables for:

  • full text filename
  • StatusByFileWatch.exe full filename
  • message buffer list
  • buffer length
  string _exeLoc = @"C:\+Storage\Programming\DotNet\StatusByFileWatch\bin\Release\StatusByFileWatch.exe"; //modify as needed
  string _txtFilename = Environment.GetEnvironmentVariable("TEMP") + @"\Logfile for Demo.txt";
  List<string> _msgs = new List<string>();
  int _bufflen = 20;

    

Then wherever you have a process that want to have messaged watched, you will:

  • delete the textfile
  • clear the message list variable
  • write a new message to the text file using the writeStatusMsg function.
  • start the StatusByFileWatch.exe with desired arguments
  • use WriteStatusMsg to add messages as some process proceeds
  • delete the text file when done displaying the messages (or do nothing and let the dialog close on its own based on the close delay argument
private void button1_Click(object sender, EventArgs e) {
   try {
    File.Delete(_txtFilename);
   }
   catch { }
   _msgs = new List<string>();
   writeStatusMsg("Starting Loop, be patient....");
   Thread.Sleep(2000);
   //run the watcher exe
   try {
    System.Diagnostics.Process.Start(_exeLoc, "\"" + _txtFilename + "\" 7000");
   }
   catch { }
   //run a loop that does enough work to block the UI from updating
   for (int i = 1; i < 30; i++) {
    //write message to the text file
    writeStatusMsg("Doing Loop " + i.ToString() + " be patient....");
    Thread.Sleep(500);
   }
   //delete message file to close watcher dialog
   try {
    File.Delete(_txtFilename);
   }
   catch { }
  }
  

Notice that this automatically trims off the first message if the message list length is exceeded.

private void writeStatusMsg (string msg) {
   //add to message list, but do not exceed buffer
   if (_msgs.Count >= _bufflen)
    _msgs.RemoveAt(0);
   //add message
   _msgs.Add(_msgIndex.ToString() + "," + msg);
   _msgIndex++;
   //try to write to file
   try {
    TextToFile(_txtFilename, _msgs.ToArray());
   }
   catch { }
  }

The TextToFile function is in the demo code.

Every language will have tools for starting an external exe, and writing to and deleting text files, so this pattern can be adopted to any language.

Points of Interest

One very important point is that the watcher must read the text file in a way that does not prevent the program being watched, from writing to the file. This function does that nicely:

public static bool TextFiletoList(string fName, out List<string> fileLines) {
   fileLines = new List<string>();
   if (File.Exists(fName)) {
    FileStream fs = new FileStream(fName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    using (StreamReader sReader = new StreamReader(fs)) {
     string text = sReader.ReadLine();
     while (text != null) {
      fileLines.Add(text);
      text = sReader.ReadLine();
     }

    }
   }
   if (fileLines.Count > 0) { return true; }
   else { return false; }
  }

the line that makes the FileStream is critical.

There are many improvements and customizations that could be done, such as a progress bar in the message dialog. If you established certain keywords in the messages, you could do all kinds of things besides just show messages. Take that to the extreme and you are essentially serializing what you want the state of the dialog to be, and the dialog updates each time the state is posted.

The tricky part about that is mixing it with other languages that may not have deserialization functions waiting to go. I had to write my own for AutoLisp, because the default way of talking between AutoCad and .net (called a resultbuffer...) does unkind things to your data as it passes back and forth.

This prog does not get complicated though, just uses simple numbered messages in the text file.

History

1st Release  10-18-12.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

James Maeding
Software Developer
United States United States
I am a Civil Engineer that writes programs as needed. The Civil industry is in a big transition from fragmented design methods and data, to more encapsulated objects that keep things cleaner. You must share the items in ways that are lightweight though, and be kind to users when connected objects cannot be found. That pursuit makes this a fun time to be in the industry.

Comments and Discussions

 
QuestionExample for usage PinmemberPierre de la Verre10-Jul-14 7:42 
GeneralMy vote of 5 Pinmemberdxlee23-Oct-12 2:25 
GeneralNice! PinmemberFrosty722-Oct-12 12:00 
GeneralRe: Nice! PinmemberJames Maeding22-Oct-12 12:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.1 | Last Updated 18 Oct 2012
Article Copyright 2012 by James Maeding
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid