Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Monitoring file changes and changing data within the file...

Monitoring file changes and changing data within the file...

Scheduled Pinned Locked Moved C#
helpquestion
12 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J JD86

    What would be a good way to monitor a .ini file? What I want to do is when the file has changed, I need to read the file and find specific text and change it and save the file. I've attempted the file system watcher with little luck. The problem is it is firing before the file is unlocked. I have also tried to put a method in there to check if the file was locked which basically opens the file and on exception returns true if locked otherwise false. I have also tried a looping method like this:

    private void WriteFile(string file, StringBuilder sb, string oldValue)
    {
    StreamWriter sw = null;
    try
    {
    sw = new StreamWriter(file, false);
    sw.Write(sb.ToString());
    sw.Close();

                // Log
                EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
            }
            catch (IOException)
            {
                // Keep trying till the file is unlocked
                WriteFile(file, sb, oldValue);
            }
            finally
            {
                if (sw != null)
                {
                    sw.Close();
                    sw.Dispose();
                }
            }
        }
    

    It still errored out after it changes the value a couple times in a row. It changes it a couple times but then ends up with a uncaught IOException somehow

    L Offline
    L Offline
    Lost User
    wrote on last edited by
    #3

    JD86 wrote:

    It changes it a couple times but then ends up with a uncaught IOException somehow

    catch (IOException)
    {
    // Log the exception here!!

    // Keep trying till the file is unlocked
    WriteFile(file, sb, oldValue);
    

    }

    You should log all exceptions; I'm betting that your WriteFile is causing the new exception, which would throw something "unhandled". So, wrap that in a try-construction too, or move it somewhere else. I'd also recommend using a using block, as opposed to a try-finally with explicit dispose - it's a bit more readable.

    Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

    1 Reply Last reply
    0
    • L Lost User

      You can use this method in a loop until the ini file closed.

      protected virtual bool IsFileLocked(FileInfo file)
      {
      FileStream stream = null;

      try
      {
          stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
      }
      catch (IOException)
      {
          //the file is unavailable because it is:
          //still being written to
          //or being processed by another thread
          //or does not exist (has already been processed)
          return true;
      }
      finally
      {
          if (stream != null)
              stream.Close();
      }
      
      //file is not locked
      return false;
      

      }

      P Offline
      P Offline
      Pete OHanlon
      wrote on last edited by
      #4

      The OP could try this, but there's a race condition here. What happens if he calls this method, and it returns false, and then he opens the file but an external process has taken a lock on the file?

      *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

      "Mind bleach! Send me mind bleach!" - Nagy Vilmos

      CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

      1 Reply Last reply
      0
      • J JD86

        What would be a good way to monitor a .ini file? What I want to do is when the file has changed, I need to read the file and find specific text and change it and save the file. I've attempted the file system watcher with little luck. The problem is it is firing before the file is unlocked. I have also tried to put a method in there to check if the file was locked which basically opens the file and on exception returns true if locked otherwise false. I have also tried a looping method like this:

        private void WriteFile(string file, StringBuilder sb, string oldValue)
        {
        StreamWriter sw = null;
        try
        {
        sw = new StreamWriter(file, false);
        sw.Write(sb.ToString());
        sw.Close();

                    // Log
                    EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
                }
                catch (IOException)
                {
                    // Keep trying till the file is unlocked
                    WriteFile(file, sb, oldValue);
                }
                finally
                {
                    if (sw != null)
                    {
                        sw.Close();
                        sw.Dispose();
                    }
                }
            }
        

        It still errored out after it changes the value a couple times in a row. It changes it a couple times but then ends up with a uncaught IOException somehow

        P Offline
        P Offline
        Pete OHanlon
        wrote on last edited by
        #5

        I would be tempted to rewrite this method like this:

        private static readonly object SyncLock = new object();
        private void WriteFile(string file, StringBuilder sb, string oldValue)
        {
        try
        {
        using (StreamWriter sw = new StreamWriter(file, false))
        {
        sw.Write(sb.ToString());
        }
        // Log
        EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
        }
        catch (IOException)
        {
        lock (SyncLock)
        {
        // Wait for 200 milliseconds
        Monitor.Wait(SyncLock, 200);
        }
        // Keep trying till the file is unlocked
        WriteFile(file, sb, oldValue);
        }
        }

        The using statement removes the need to explicitly close the stream, and the lock/Monitor elements help to pause the next call to WriteFile for 200 milliseconds. Without this, you have a tight loop in there with execution of WriteFile happening immediately on failure.

        *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

        "Mind bleach! Send me mind bleach!" - Nagy Vilmos

        CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

        D 1 Reply Last reply
        0
        • J JD86

          What would be a good way to monitor a .ini file? What I want to do is when the file has changed, I need to read the file and find specific text and change it and save the file. I've attempted the file system watcher with little luck. The problem is it is firing before the file is unlocked. I have also tried to put a method in there to check if the file was locked which basically opens the file and on exception returns true if locked otherwise false. I have also tried a looping method like this:

          private void WriteFile(string file, StringBuilder sb, string oldValue)
          {
          StreamWriter sw = null;
          try
          {
          sw = new StreamWriter(file, false);
          sw.Write(sb.ToString());
          sw.Close();

                      // Log
                      EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
                  }
                  catch (IOException)
                  {
                      // Keep trying till the file is unlocked
                      WriteFile(file, sb, oldValue);
                  }
                  finally
                  {
                      if (sw != null)
                      {
                          sw.Close();
                          sw.Dispose();
                      }
                  }
              }
          

          It still errored out after it changes the value a couple times in a row. It changes it a couple times but then ends up with a uncaught IOException somehow

          B Offline
          B Offline
          BobJanova
          wrote on last edited by
          #6

          Use the FileSystemWatcher, when it notifies you of a change put an entry on a queue with a retrieval time of 1 second (or 200ms or whatever is appropriate in the future), and have another thread which pulls things off that queue at the right time and actions them. In this case the action is 'read file, find text, replace, write file'. If it fails, re-queue it.

          P 1 Reply Last reply
          0
          • B BobJanova

            Use the FileSystemWatcher, when it notifies you of a change put an entry on a queue with a retrieval time of 1 second (or 200ms or whatever is appropriate in the future), and have another thread which pulls things off that queue at the right time and actions them. In this case the action is 'read file, find text, replace, write file'. If it fails, re-queue it.

            P Offline
            P Offline
            Pete OHanlon
            wrote on last edited by
            #7

            Based on the description, I believe this is what the OP has said he's done (all except for the pause bit).

            *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

            "Mind bleach! Send me mind bleach!" - Nagy Vilmos

            CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

            J 2 Replies Last reply
            0
            • P Pete OHanlon

              I would be tempted to rewrite this method like this:

              private static readonly object SyncLock = new object();
              private void WriteFile(string file, StringBuilder sb, string oldValue)
              {
              try
              {
              using (StreamWriter sw = new StreamWriter(file, false))
              {
              sw.Write(sb.ToString());
              }
              // Log
              EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
              }
              catch (IOException)
              {
              lock (SyncLock)
              {
              // Wait for 200 milliseconds
              Monitor.Wait(SyncLock, 200);
              }
              // Keep trying till the file is unlocked
              WriteFile(file, sb, oldValue);
              }
              }

              The using statement removes the need to explicitly close the stream, and the lock/Monitor elements help to pause the next call to WriteFile for 200 milliseconds. Without this, you have a tight loop in there with execution of WriteFile happening immediately on failure.

              *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

              "Mind bleach! Send me mind bleach!" - Nagy Vilmos

              CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

              D Offline
              D Offline
              Dave Kreskowiak
              wrote on last edited by
              #8

              Whoa there Slick! I see a possible StackOverflow waiting to happen if the file never gets unlocked.

              A guide to posting questions on CodeProject[^]
              Dave Kreskowiak

              P 1 Reply Last reply
              0
              • D Dave Kreskowiak

                Whoa there Slick! I see a possible StackOverflow waiting to happen if the file never gets unlocked.

                A guide to posting questions on CodeProject[^]
                Dave Kreskowiak

                P Offline
                P Offline
                Pete OHanlon
                wrote on last edited by
                #9

                Indeed, but I'm only working with the OPs original code - yes, if it were my code, I'd add in terminating conditions. As I don't know what the OPs ultimate use case is here, I'm loathe to suggest this - I've just had to assume that the lock has a finite limit.

                *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                D 1 Reply Last reply
                0
                • P Pete OHanlon

                  Indeed, but I'm only working with the OPs original code - yes, if it were my code, I'd add in terminating conditions. As I don't know what the OPs ultimate use case is here, I'm loathe to suggest this - I've just had to assume that the lock has a finite limit.

                  *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                  "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                  CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                  D Offline
                  D Offline
                  Dave Kreskowiak
                  wrote on last edited by
                  #10

                  Pete O'Hanlon wrote:

                  I've just had to assume that the lock has a finite limit.

                  True. I don't know any more about his requirements than you. I just wanted to point out that it's not the ultimate solution for anyone else just scrounging for code.

                  Pete O'Hanlon wrote:

                  I'm loathe to suggest this

                  Kinda makes you want to take a long shower, doesn't it? ;)

                  A guide to posting questions on CodeProject[^]
                  Dave Kreskowiak

                  1 Reply Last reply
                  0
                  • P Pete OHanlon

                    Based on the description, I believe this is what the OP has said he's done (all except for the pause bit).

                    *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                    "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                    CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                    J Offline
                    J Offline
                    JD86
                    wrote on last edited by
                    #11

                    Sorry for the delay responses! Just had a baby girl :-) Anyways let me explain. I'm setting up a multi-tenant quickbooks environment. The problem is as we probably all know is it wasn't really designed for multi-tenancy. Now everything works fine with what I have except the username is populated on a program level. So in the ProgramData directory (All Users) there is a qbw.ini file that contains LASTUSERNAME=. Each time a user launches quickbooks it reads this information and prepopulated the username field for the company database login. I don't want people seeing other peoples logins. Most just use Admin which isn't a big deal but some use their company name. So I don't want another company seeing that. So my idea is to monitor that file for updates using a file system watcher and changing that value in the INI file to blank. So basically changing something like this: "LASTUSERNAME=Admin" to this: "LASTUSERNAME=" Quickbooks does not place a permanent lock on this file. So we don't have to worry about quickbooks locking it for a long period of time. I'm trying suggestions as we speak. I'm adding an error count to stop the service if an exception happens so many times within a specific time period. Hopefully this will stop an overflow exception like you were talking about. I can make something to restart the service ever so often. Not the best plan but so far thats what I got!

                    1 Reply Last reply
                    0
                    • P Pete OHanlon

                      Based on the description, I believe this is what the OP has said he's done (all except for the pause bit).

                      *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                      "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                      CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                      J Offline
                      J Offline
                      JD86
                      wrote on last edited by
                      #12

                      Alright so here is what I ended up with. It seems to work... catches the IO exceptions and continues running. So far it is working good enough for me

                      using System;
                      using System.Diagnostics;
                      using System.IO;
                      using System.ServiceProcess;
                      using System.Text;
                      using System.Threading;

                      namespace QBiniMonitor
                      {
                      public partial class QBMonitor : ServiceBase
                      {
                      // Watches the qbw.ini directory
                      FileSystemWatcher watcher2012;
                      FileSystemWatcher watcher2011;

                          // Path to the folder where qbw.ini is stored
                          string QB2012 = Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%") + @"\\Intuit\\QuickBooks 2012\\";
                          string QB2011 = Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%") + @"\\Intuit\\QuickBooks 2011\\";
                      
                          // Version
                          enum Version
                          {
                              QB2011,
                              QB2012
                          }
                      
                          /// /// Constructor
                          /// 
                          public QBMonitor()
                          {
                              InitializeComponent();
                          }
                      
                          /// /// When service starts we need to start our FileSystemWatcher
                          /// 
                          protected override void OnStart(string\[\] args)
                          {
                              StartNewWatcher(Version.QB2011);
                              StartNewWatcher(Version.QB2012);
                          }
                      
                          /// /// Starts the FileSystemWatcher for Quickbooks 2012 & 2011
                          /// 
                          private void StartNewWatcher(Version watcherVersion)
                          {
                              if (watcherVersion == Version.QB2011)
                              {
                                  watcher2011 = new FileSystemWatcher();
                                  watcher2011.Path = QB2011;
                                  watcher2011.Filter = "qbw.ini";
                                  watcher2011.NotifyFilter = NotifyFilters.LastWrite;
                      
                                  watcher2011.Changed += new FileSystemEventHandler(watcher\_Changed);
                      
                                  // Start the watcher
                                  StartStopWatcher(Version.QB2011, true);
                              }
                              else if (watcherVersion == Version.QB2012)
                              {
                                  watcher2012 = new FileSystemWatcher();
                                  watcher2012.Path = QB2012;
                                  watcher2012.Filter = "qbw.ini";
                                  watcher2012.NotifyFilter = NotifyFilters.LastWrite;
                      
                                  watcher2012.Changed += new FileSystemEventHandler(watcher\_Changed);
                      
                                  // Start the watcher
                                  StartStopWatcher(Version.QB2012, true);
                              }
                          }
                      
                          ///
                      
                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups