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
    #2

    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 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

      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