none
File system watcher: who wrote into the file?

    Question

  • Hi!

    I have two instances of app that both can write into shared file (let they be named as App1 and App2).

    If first instance wrote something into the file, the second instance should read a new content and write some changesinto this file and vice versa.

    I trying to use FileSystemWatcher in order to monitor file changes.

    The matter is FileSystemWatcher arises notifycation event for App1 even if the file was changed by App1 itself. So it pulls me into the loop. Of course, I can disable event arising right before file writing and enable it immediately after write.

    I'm not sure it is a good idea. Is there some other way to prevent event arising when app writes into the file itself?


    • Edited by Ha3R Saturday, June 22, 2013 11:06 PM edit
    Saturday, June 22, 2013 11:03 PM

Answers

  • I just tested it out by creating a new form project that uses a filesystemwatcher to monitor the same file that i change by using a button and a textbox on the same form. If i set (EnableRaisingEvents) to False just before changing the file and then back to True after changing the file it stops the MessageBox in the (FileChanged) sub from popping up.

    Public Class Form1
        Dim fsw As New IO.FileSystemWatcher()
    
        Private Sub Form1_Load_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            fsw.Path = "C:\testfolder" 'Set this to the full directory path that has your file in it
            fsw.Filter = "testfile.txt" 'The name of the file your monitoring
            fsw.IncludeSubdirectories = False 'Not needed if you are only monitoring 1 specific file
            fsw.EnableRaisingEvents = True
            AddHandler fsw.Changed, AddressOf FileChanged
        End Sub
    
        Private Sub FileChanged(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs)
            MessageBox.Show("Changed File = " & e.Name & "    Change Type = " & e.ChangeType.ToString)
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            fsw.EnableRaisingEvents = False
            System.IO.File.WriteAllLines("C:\testfolder\testfile.txt", TextBox1.Lines)
            fsw.EnableRaisingEvents = True
        End Sub
    End Class

    Sunday, June 23, 2013 12:31 AM
  • I displayed the handle of the form that is showing the messagebox in the message and had the forms show there handle as there title text so you can see that it is not the same instance of the program that is showning the messagebox.

    If that is a comment on the proposal I made, then your implementation appears to be lacking some essential feature.

    This example writes the instance identifier into the log record.  It responds to every file change (including those it creates with its own writes) but only processes those changes created by other instances.

    Public Class Form1
    
        Dim fsw As New IO.FileSystemWatcher()
        Dim WatchFolder As String = "C:\users\Public"
        Dim WatchFile As String = "Logging.log"
        Dim logfile As String = System.IO.Path.Combine(WatchFolder, WatchFile)
        Dim mytag As String
    
        Delegate Sub AppendText(ByVal Text As String)
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            mytag = Me.Handle.ToString
            fsw.Path = WatchFolder
            fsw.Filter = WatchFile
            fsw.EnableRaisingEvents = True
            AddHandler fsw.Changed, AddressOf FileChanged
            Me.Text = mytag
        End Sub
    
        Private Sub FileChanged(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs)
            TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), "Change: " & e.Name & " " & e.ChangeType.ToString & vbCrLf)
            Dim str() As String = System.IO.File.ReadAllLines(logfile)
            Dim Latest As String = str(str.Count - 1)
            TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), Latest & vbCrLf)
            If Latest.StartsWith(mytag) Then
                TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), "Own message - ignore" & vbCrLf)
            Else
                TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), "Other message - process" & vbCrLf)
            End If
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim sw As System.IO.StreamWriter = System.IO.File.AppendText(logfile)
            sw.WriteLine(mytag & " " & Now)
            sw.flush()
            sw.close()
        End Sub
    
    End Class

    Sunday, June 23, 2013 1:11 PM
  • So I made it so 3 or more apps have access to work on the last line in ChangeFile.txt when a message from one of the other apps that added the last line into ChangeFile.txt lets the detecting apps know which one is their turn by the message posted in the LastUserToMakeChanges.txt file.

    Alpha code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
        Dim k As Integer = 1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Alpha"
            If File.Exists(Path1) = False Then
                Dim fs1 As FileStream = File.Create(Path1)
                fs1.Close()
                My.Computer.FileSystem.WriteAllText(Path1, "Alpha text to change" & vbCrLf, False)
            End If
            If File.Exists(Path2) = False Then
                Dim fs2 As FileStream = File.Create(Path2)
                fs2.Close()
                My.Computer.FileSystem.WriteAllText(Path2, "Alpha 2" & vbCrLf, False) ' Alpha 2 tells Beta to start the process
            End If
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine.Contains("Alpha") Or LUTMCLastLine.Contains("1") = False Then
                    j += 1
                    Label1.Text = "Detected for Alpha " & j.ToString & " times."
                    Exit Sub
                Else
                    System.Threading.Thread.Sleep(500)
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                    Label3.BackColor = Color.LimeGreen
                    j += 1
                    Label1.Text = "Detected for Alpha " & j.ToString & " times."
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand1 As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand1.Next(0, 1000)))
                Label2.Text = "Last msg processed = " & ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Alpha text")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
                Label5.Text = "Number of msgs processed = " & k.ToString
                k += 1
    
                System.Threading.Thread.Sleep(200)
    
                Dim Rand2 As New Random
                Dim PassOffTo As Integer = 0
                Do Until PassOffTo <> 1 AndAlso PassOffTo <> 0
                    PassOffTo = Rand2.Next(1, 4)
                Loop
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Alpha " & PassOffTo.ToString)
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Label3.BackColor = Color.OrangeRed
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
                j += 1
                Label1.Text = "Detected for Alpha " & j.ToString & " times."
            End Try
    
        End Sub
    
    End Class

    Beta code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
        Dim k As Integer = 1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Beta"
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine.Contains("Beta") Or LUTMCLastLine.Contains("2") = False Then
                    j += 1
                    Label1.Text = "Detected for Beta " & j.ToString & " times."
                    Exit Sub
                Else
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                    Label3.BackColor = Color.LimeGreen
                    j += 1
                    Label1.Text = "Detected for Beta " & j.ToString & " times."
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand1 As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand1.Next(0, 1000)))
                Label2.Text = "Last msg processed = " & ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Beta text")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
                Label5.Text = "Number of msgs processed = " & k.ToString
                k += 1
    
                System.Threading.Thread.Sleep(200)
    
                Dim Rand2 As New Random
                Dim PassOffTo As Integer = 0
                Do Until PassOffTo <> 2 AndAlso PassOffTo <> 0
                    PassOffTo = Rand2.Next(1, 4)
                Loop
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Beta " & PassOffTo.ToString)
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Label3.BackColor = Color.OrangeRed
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
                j += 1
                Label1.Text = "Detected for Beta " & j.ToString & " times."
            End Try
    
        End Sub
    
    End Class
    

    Gamma code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
        Dim k As Integer = 1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Gamma"
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine.Contains("Gamma") Or LUTMCLastLine.Contains("3") = False Then
                    j += 1
                    Label1.Text = "Detected for Gamma " & j.ToString & " times."
                    Exit Sub
                Else
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                    Label3.BackColor = Color.LimeGreen
                    j += 1
                    Label1.Text = "Detected for Gamma " & j.ToString & " times."
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand1 As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand1.Next(0, 1000)))
                Label2.Text = "Last msg processed = " & ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Gamma text")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
                Label5.Text = "Number of msgs processed = " & k.ToString
                k += 1
    
                System.Threading.Thread.Sleep(200)
    
                Dim Rand2 As New Random
                Dim PassOffTo As Integer = 0
                Do Until PassOffTo <> 3 AndAlso PassOffTo <> 0
                    PassOffTo = Rand2.Next(1, 4)
                Loop
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Gamma " & PassOffTo.ToString)
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Label3.BackColor = Color.OrangeRed
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
                j += 1
                Label1.Text = "Detected for Gamma " & j.ToString & " times."
            End Try
    
        End Sub
    
    End Class
    


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8

    Monday, June 24, 2013 8:55 PM
  • Well this works but the app has to be run as Admin unfortunately. And for some reason I'm displaying all of the messages instead of just the last one. And I haven't checked on how to clear the log yet.

    Option Strict On
    Option Explicit On
    
    Imports System
    Imports System.Diagnostics
    Imports System.Threading
    
    Imports System.IO
    
    Public Class Form1
    
        ' Application has to be run as Admin
    
        ' http://weblogs.asp.net/ashben/archive/2003/10/14/31773.aspx FileSystemWatcher tips
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file Question thread
        ' http://blogs.technet.com/b/janelewis/archive/2010/04/30/giving-non-administrators-permission-to-read-event-logs-windows-2003-and-windows-2008.aspx
        ' Above link is supposedly how to allow non-admin users apps to read Event Logs
    
        Public WatchFolder As FileSystemWatcher
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Text = "File Watcher"
            TextBox1.Text = "C:\Users\John\Desktop\Test Folder"
            TextBox1.SelectionStart = 0
            Control.CheckForIllegalCrossThreadCalls = False
            Try
                If Not EventLog.SourceExists("MySource") Then
                    EventLog.CreateEventSource("MySource", "MyNewLog")
                    Me.Close()' Have to close app after log created before app can write to it.
                End If
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
    
        End Sub
    
        Private Sub btn_StartWatch_Click(sender As Object, e As EventArgs) Handles Button1.Click
            WatchFolder = New System.IO.FileSystemWatcher()
    
            WatchFolder.Path = TextBox1.Text
            WatchFolder.Filter = "Testing.txt"
    
            WatchFolder.NotifyFilter = NotifyFilters.LastWrite
    
            AddHandler WatchFolder.Changed, AddressOf FilesLastWrite
    
            WatchFolder.EnableRaisingEvents = True
    
            Button1.Enabled = False
            Button2.Enabled = True
    
        End Sub
    
        Private Sub btn_Stop_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            WatchFolder.EnableRaisingEvents = False
            Button1.Enabled = True
            Button2.Enabled = False
    
        End Sub
    
        Private Sub FilesLastWrite(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
    
            If e.ChangeType = IO.WatcherChangeTypes.Changed Then
                TextBox2.Text &= "File " & e.FullPath & " has been modified" & vbCrLf
                RichTextBox1.Text = ""
                GetEventLogEntry()
            End If
    
        End Sub
    
        Private Sub GetEventLogEntry()
            Dim entry As EventLogEntry
            Dim myLog As New EventLog()
            myLog.Source = "MySource"
            For Each entry In myLog.Entries
                RichTextBox1.AppendText(myLog.Entries(myLog.Entries.Count - 1).Message)
            Next
        End Sub
    
        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim myLog As New EventLog()
            myLog.Source = "MySource"
            myLog.WriteEntry(Environment.UserName & " wrote to file." & vbCrLf)
            My.Computer.FileSystem.WriteAllText("C:\Users\John\Desktop\Test Folder\Testing.txt", TextBox1.Text, True)
        End Sub
    
    End Class


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8



    Sunday, June 23, 2013 11:17 AM
  • "I have two instances of app that both can write into shared file (let they be named as App1 and App2)."

    I started 2 instances of my program code from my above post and changed the text file from the 1st instance of the program and the 2nd instance of the program fired the FileChanged event. Then i changed the text file with the 2nd instance of the program and the first instance of the program fired the FileChanged event. I displayed the handle of the form that is showing the messagebox in the message and had the forms show there handle as there title text so you can see that it is not the same instance of the program that is showning the messagebox.

    Sunday, June 23, 2013 11:34 AM
  • I think your idea is probably a better way to do it though. 

    Perhaps.   But it's still not a very good way to do it, because it is subject to race or contention problems that can be difficult to resolve.   Identifying which app made the change is only a part of the problem. Ensufing that the two apps don't step on each other's messages needs a properly managed queue.

    Sunday, June 23, 2013 11:04 PM
  • I tested speeds from 1 millisecond to 500 milliseconds without having already added the System.Threading.Thread.Sleep entry but the apps crashed due to another process having a file open when an app tried to access the file.

    That's the contention issue I was referring to.  When the posting to the log is controlled by external events, the risk of the error cannot be avoided.  It is possible that it can be caught and handled, but that depends on the requirements of the application, and can become very complex.

    No doubt a queued method would be the way to go especially if you had more than two users where applications had to know from the queue if the user that made the last post was the one this app or that app was supposed to change the last line of.

    So to tell the story again because I forgot to copy and paste it out of the post I just deleted :( this works as follows.

    The applications are "Alpha" and "Beta". Alpha is on the left in the image below.

    A timer is used in the application to check the file LastUserToMakeChanges.txt to find out if it was the last user to make a change in the file called ChangeFile.txt. If not the application changes the last line in the file ChangeFile.txt, adds a new line and then posts its name in the file LastUserToMakeChanges.txt.

    Also due to issues with the try/catch in the timer catching errors, due to the app trying to open the file ChangeFile.txt while it was still in use by another process, the Timer1.Interval is auto incremented by 1 anytime an error is caught. This seems to be working well so far. All though I suppose it could become an issue if the timers interval was auto incremented to some drastic amount. But I'm running it right now and the timers interval on Alpha is now at 42 and Beta is at 34 which is a lot lower than 500 that I had them both set to in order not to get any errors. And they have been running for about 10 minutes now. Although there is also a Thread.Sleep of 200 between the time the file information that was changed is written into ChangeFile.txt and when the app posts its name in LastUserToMakeChanges.txt.

    I have a feeling the timers would be auto incrementing faster if all of the text from ChangeFile.txt was not being displayed in the RichTextBoxs constantly.

    "Alpha" code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Alpha"
            If File.Exists(Path1) = False Then
                Dim fs1 As FileStream = File.Create(Path1)
                fs1.Close()
                My.Computer.FileSystem.WriteAllText(Path1, "Alpha text to change" & vbCrLf, False)
            End If
            If File.Exists(Path2) = False Then
                Dim fs2 As FileStream = File.Create(Path2)
                fs2.Close()
                My.Computer.FileSystem.WriteAllText(Path2, "Alpha" & vbCrLf, False)
            End If
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine = "Alpha" Then
                    j += 1
                    Label1.Text = j.ToString
                    Exit Sub
                Else
                    System.Threading.Thread.Sleep(500)
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand.Next(0, 1000000000)))
                Label2.Text = ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Alpha text to change")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
    
                System.Threading.Thread.Sleep(200)
    
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Alpha")
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
            End Try
    
        End Sub
    
    End Class

    "Beta" code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Beta"
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine = "Beta" Then
                    j += 1
                    Label1.Text = j.ToString
                    Exit Sub
                Else
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
                Dim Rand As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand.Next(0, 1000000000)))
                Label2.Text = ChangedInfo(ChangedInfo.Count - 1)
    
            ChangedInfo.Add("Beta text to change")
    
            Dim sr3 As New System.IO.StreamWriter(Path1)
            If ChangedInfo.Count = 1 Then
                sr3.WriteLine(ChangedInfo(0))
            Else
                For i = 0 To ChangedInfo.Count - 1
                    sr3.WriteLine(ChangedInfo(i))
                Next
            End If
            sr3.Close()
    
            System.Threading.Thread.Sleep(200)
    
            Dim sr4 As New System.IO.StreamWriter(Path2)
            sr4.WriteLine("Beta")
            sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
            End Try
    
    
        End Sub
    
    End Class


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8




    Monday, June 24, 2013 10:16 AM
  • Hi Ha3R,

    I believe you'll have to use some combination of what the others have already shown you, mostly depending on how you need your data file formatted.  You could concatenate values within one file or use multiple files to store different aspects of each transaction. But regardless of how you decide to share the data file, the simplest way to prevent multiple user contention issues is to use a lock file.

    Before your application attempts to open the shared data file, it first tries to create a lock file with a specific file name and/or extension, using a File Create method which does not allow overwriting an existing file.  This lock file can be a zero byte file, or it might contain a small amount of data pertaining to the user who took the lock.

    Since the application is attempting to create the lock file without overwrite permission, and every instance of the application will attempt to create the same lock file name, an exception will occur if the lock file already exists and you can catch this to indicate that the file is already in use by another program.  Even if two or more instances attempt to take a lock at the same time, only the first to be processed by Windows can succeed and the others must fail.

    After the application is done editing the data file, it can delete the lock file that it created.

    The downside is that this method becomes inefficient quickly if there are many frequent changes to the data file.  But if the changes tend to come sporadically from various clients without any one heavy load then it may work just fine.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Monday, June 24, 2013 9:59 PM

All replies

  • I have not tested this but, you could try enabling and disabling the FileSystemWatcher by setting the (EnableRaisingEvents) property to True or False. False before writing file and True when done. Just change (FileSystemWatcher1) to whatever the name of yours is.

    FileSystemWatcher1.EnableRaisingEvents = True
    FileSystemWatcher1.EnableRaisingEvents = False
    

    Saturday, June 22, 2013 11:31 PM
  • I just tested it out by creating a new form project that uses a filesystemwatcher to monitor the same file that i change by using a button and a textbox on the same form. If i set (EnableRaisingEvents) to False just before changing the file and then back to True after changing the file it stops the MessageBox in the (FileChanged) sub from popping up.

    Public Class Form1
        Dim fsw As New IO.FileSystemWatcher()
    
        Private Sub Form1_Load_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            fsw.Path = "C:\testfolder" 'Set this to the full directory path that has your file in it
            fsw.Filter = "testfile.txt" 'The name of the file your monitoring
            fsw.IncludeSubdirectories = False 'Not needed if you are only monitoring 1 specific file
            fsw.EnableRaisingEvents = True
            AddHandler fsw.Changed, AddressOf FileChanged
        End Sub
    
        Private Sub FileChanged(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs)
            MessageBox.Show("Changed File = " & e.Name & "    Change Type = " & e.ChangeType.ToString)
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            fsw.EnableRaisingEvents = False
            System.IO.File.WriteAllLines("C:\testfolder\testfile.txt", TextBox1.Lines)
            fsw.EnableRaisingEvents = True
        End Sub
    End Class

    Sunday, June 23, 2013 12:31 AM
  • +1 for (looking like - OP may yet come back with some other requirement, lol) an elegant solution.

    --
    Andrew

    Sunday, June 23, 2013 12:43 AM
  • +1 for (looking like - OP may yet come back with some other requirement, lol) an elegant solution.

    --
    Andrew


    Thanks.... I figured i would post my test code with a few comments to help show what i was doing.  :)
    Sunday, June 23, 2013 1:06 AM
  • I have two instances of app that both can write into shared file (let they be named as App1 and App2).

    There are several different ways of communicating between applications, and using a shared file is probably one of the most difficult to manage. You can suppress the change events when you make a change, but you will run into race or contention problems at some stage.

    A better solution is to respond to all change events, but to ensure that the message that is put to the file contains an identifier that the responding application can use to determine whether the latest change was its own or was from a different applicaton. The main window hWnd is probably suitable.

    You could also consider changing your design to an alternative, such as System Messaging:
    http://msdn.microsoft.com/en-us/library/system.messaging.message.aspx

    Sunday, June 23, 2013 8:58 AM
  • Thanks for replies!

    I have already implemented this solution (as I wrote above).

    It seems like there is no way to determine which app wrote into the file.

    Sunday, June 23, 2013 9:09 AM
  • Thanks for replies!

    I have already implemented this solution (as I wrote above).

    It seems like there is no way to determine which app wrote into the file.

    I believe that may be inaccurate to a degree. You may not be able to tell which App wrote into the file but you may be able to tell which User wrote into the file last. Unfortunately in my efforts I can not get this working. But supposedly you can set the Folder, which the file is in, or the File itselfs (on Win 7) Properties, Security (advanced), Auditing (Press continue), Auditing (Add) press Object Types and I set to User, Group or Built-In Security Principal, press Location and I only have my Machine, Check Names and I put Everyone. Press O.K. and I check successful for everything for testing. Then O.K., Apply, O.K., O.K., O.K. and that should set Auditing (I did it for the file, not the Folder).

    Anyhow when that is done supposedly if someone accesses the File you can use Filewatcher to call a Function to get the last log entry entered in the Event Log called "Security" which should note the User that just did any of those checked possibilities to that file. But my Security Log only shows that I performed the addition of Auditing to the file and never shows when anything is done to the file.

    Also I have to run my application with Admin privileges but I believe you can set Event Viewer or something to allow access to read logs without Admin privileges. I just haven't looked into it yet. And supposedly you can get Event Logs across the Network in case the File being audited is on a network share or something.

    Anyhow here's my code so far and an image of the last retrieved event log (which happens to be adding auditing to the file) from when I changed the File using Notepad.

    This blog article looks like it covers allowing non-admin users to read Even Logs but may be too much of a pain.

    http://blogs.technet.com/b/janelewis/archive/2010/04/30/giving-non-administrators-permission-to-read-event-logs-windows-2003-and-windows-2008.aspx

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' Application has to be run as Admin
    
        ' http://weblogs.asp.net/ashben/archive/2003/10/14/31773.aspx FileSystemWatcher tips
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file Question thread
    
        Public WatchFolder As FileSystemWatcher
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Text = "File Watcher"
            TextBox1.Text = "C:\Users\John\Desktop\Test Folder"
            TextBox1.SelectionStart = 0
            Control.CheckForIllegalCrossThreadCalls = False
        End Sub
    
        Private Sub btn_StartWatch_Click(sender As Object, e As EventArgs) Handles Button1.Click
            WatchFolder = New System.IO.FileSystemWatcher()
    
            WatchFolder.Path = TextBox1.Text
            WatchFolder.Filter = "Testing.txt"
    
            WatchFolder.NotifyFilter = NotifyFilters.LastWrite
    
            AddHandler WatchFolder.Changed, AddressOf FilesLastWrite
    
            WatchFolder.EnableRaisingEvents = True
    
            Button1.Enabled = False
            Button2.Enabled = True
    
        End Sub
    
        Private Sub btn_Stop_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            WatchFolder.EnableRaisingEvents = False
            Button1.Enabled = True
            Button2.Enabled = False
    
        End Sub
    
        Private Sub FilesLastWrite(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
    
            If e.ChangeType = IO.WatcherChangeTypes.Changed Then
                TextBox2.Text &= "File " & e.FullPath & " has been modified" & vbCrLf
                RichTextBox1.Text = ""
                RichTextBox1.AppendText(GetLastEntry("Security") & vbCrLf)
            End If
    
        End Sub
    
        Public Function GetLastEntry(ByRef LogsName As String) As String
    
            Dim LogEntries() As EventLog = EventLog.GetEventLogs()
            Dim LogEntry As EventLog = Nothing
    
            For Each LogEntry In LogEntries
                If LogEntry.LogDisplayName = LogsName Then
                    Exit For
                End If
            Next
    
            Return LogEntry.Entries(LogEntry.Entries.Count - 1).Message
    
        End Function
    
    End Class


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8




    Sunday, June 23, 2013 10:09 AM
  • Well this works but the app has to be run as Admin unfortunately. And for some reason I'm displaying all of the messages instead of just the last one. And I haven't checked on how to clear the log yet.

    Option Strict On
    Option Explicit On
    
    Imports System
    Imports System.Diagnostics
    Imports System.Threading
    
    Imports System.IO
    
    Public Class Form1
    
        ' Application has to be run as Admin
    
        ' http://weblogs.asp.net/ashben/archive/2003/10/14/31773.aspx FileSystemWatcher tips
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file Question thread
        ' http://blogs.technet.com/b/janelewis/archive/2010/04/30/giving-non-administrators-permission-to-read-event-logs-windows-2003-and-windows-2008.aspx
        ' Above link is supposedly how to allow non-admin users apps to read Event Logs
    
        Public WatchFolder As FileSystemWatcher
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Text = "File Watcher"
            TextBox1.Text = "C:\Users\John\Desktop\Test Folder"
            TextBox1.SelectionStart = 0
            Control.CheckForIllegalCrossThreadCalls = False
            Try
                If Not EventLog.SourceExists("MySource") Then
                    EventLog.CreateEventSource("MySource", "MyNewLog")
                    Me.Close()' Have to close app after log created before app can write to it.
                End If
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
    
        End Sub
    
        Private Sub btn_StartWatch_Click(sender As Object, e As EventArgs) Handles Button1.Click
            WatchFolder = New System.IO.FileSystemWatcher()
    
            WatchFolder.Path = TextBox1.Text
            WatchFolder.Filter = "Testing.txt"
    
            WatchFolder.NotifyFilter = NotifyFilters.LastWrite
    
            AddHandler WatchFolder.Changed, AddressOf FilesLastWrite
    
            WatchFolder.EnableRaisingEvents = True
    
            Button1.Enabled = False
            Button2.Enabled = True
    
        End Sub
    
        Private Sub btn_Stop_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            WatchFolder.EnableRaisingEvents = False
            Button1.Enabled = True
            Button2.Enabled = False
    
        End Sub
    
        Private Sub FilesLastWrite(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
    
            If e.ChangeType = IO.WatcherChangeTypes.Changed Then
                TextBox2.Text &= "File " & e.FullPath & " has been modified" & vbCrLf
                RichTextBox1.Text = ""
                GetEventLogEntry()
            End If
    
        End Sub
    
        Private Sub GetEventLogEntry()
            Dim entry As EventLogEntry
            Dim myLog As New EventLog()
            myLog.Source = "MySource"
            For Each entry In myLog.Entries
                RichTextBox1.AppendText(myLog.Entries(myLog.Entries.Count - 1).Message)
            Next
        End Sub
    
        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim myLog As New EventLog()
            myLog.Source = "MySource"
            myLog.WriteEntry(Environment.UserName & " wrote to file." & vbCrLf)
            My.Computer.FileSystem.WriteAllText("C:\Users\John\Desktop\Test Folder\Testing.txt", TextBox1.Text, True)
        End Sub
    
    End Class


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8



    Sunday, June 23, 2013 11:17 AM
  • "I have two instances of app that both can write into shared file (let they be named as App1 and App2)."

    I started 2 instances of my program code from my above post and changed the text file from the 1st instance of the program and the 2nd instance of the program fired the FileChanged event. Then i changed the text file with the 2nd instance of the program and the first instance of the program fired the FileChanged event. I displayed the handle of the form that is showing the messagebox in the message and had the forms show there handle as there title text so you can see that it is not the same instance of the program that is showning the messagebox.

    Sunday, June 23, 2013 11:34 AM
  • I displayed the handle of the form that is showing the messagebox in the message and had the forms show there handle as there title text so you can see that it is not the same instance of the program that is showning the messagebox.

    If that is a comment on the proposal I made, then your implementation appears to be lacking some essential feature.

    This example writes the instance identifier into the log record.  It responds to every file change (including those it creates with its own writes) but only processes those changes created by other instances.

    Public Class Form1
    
        Dim fsw As New IO.FileSystemWatcher()
        Dim WatchFolder As String = "C:\users\Public"
        Dim WatchFile As String = "Logging.log"
        Dim logfile As String = System.IO.Path.Combine(WatchFolder, WatchFile)
        Dim mytag As String
    
        Delegate Sub AppendText(ByVal Text As String)
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            mytag = Me.Handle.ToString
            fsw.Path = WatchFolder
            fsw.Filter = WatchFile
            fsw.EnableRaisingEvents = True
            AddHandler fsw.Changed, AddressOf FileChanged
            Me.Text = mytag
        End Sub
    
        Private Sub FileChanged(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs)
            TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), "Change: " & e.Name & " " & e.ChangeType.ToString & vbCrLf)
            Dim str() As String = System.IO.File.ReadAllLines(logfile)
            Dim Latest As String = str(str.Count - 1)
            TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), Latest & vbCrLf)
            If Latest.StartsWith(mytag) Then
                TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), "Own message - ignore" & vbCrLf)
            Else
                TextBox1.Invoke(New AppendText(AddressOf TextBox1.AppendText), "Other message - process" & vbCrLf)
            End If
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim sw As System.IO.StreamWriter = System.IO.File.AppendText(logfile)
            sw.WriteLine(mytag & " " & Now)
            sw.flush()
            sw.close()
        End Sub
    
    End Class

    Sunday, June 23, 2013 1:11 PM
  • "If that is a comment on the proposal I made, then your implementation appears to be lacking some essential feature."

    No. I was just trying to show which instance was firing the FileChanged event thinking that could be used to let the other instance know it is now able to change the file. When the first program instance changes the file it will trigger the FileChanged event in the second instance letting it know it can now change the file. Then when the second instance changes the file the FileChanged even in the first instance will be triggered to let it know it can now change the file.

    I think your idea is probably a better way to do it though.  :)

    Sunday, June 23, 2013 2:25 PM
  • I think your idea is probably a better way to do it though. 

    Perhaps.   But it's still not a very good way to do it, because it is subject to race or contention problems that can be difficult to resolve.   Identifying which app made the change is only a part of the problem. Ensufing that the two apps don't step on each other's messages needs a properly managed queue.

    Sunday, June 23, 2013 11:04 PM
  • I tested speeds from 1 millisecond to 500 milliseconds without having already added the System.Threading.Thread.Sleep entry but the apps crashed due to another process having a file open when an app tried to access the file.

    That's the contention issue I was referring to.  When the posting to the log is controlled by external events, the risk of the error cannot be avoided.  It is possible that it can be caught and handled, but that depends on the requirements of the application, and can become very complex.

    Monday, June 24, 2013 9:41 AM
  • I tested speeds from 1 millisecond to 500 milliseconds without having already added the System.Threading.Thread.Sleep entry but the apps crashed due to another process having a file open when an app tried to access the file.

    That's the contention issue I was referring to.  When the posting to the log is controlled by external events, the risk of the error cannot be avoided.  It is possible that it can be caught and handled, but that depends on the requirements of the application, and can become very complex.

    No doubt a queued method would be the way to go especially if you had more than two users where applications had to know from the queue if the user that made the last post was the one this app or that app was supposed to change the last line of.

    So to tell the story again because I forgot to copy and paste it out of the post I just deleted :( this works as follows.

    The applications are "Alpha" and "Beta". Alpha is on the left in the image below.

    A timer is used in the application to check the file LastUserToMakeChanges.txt to find out if it was the last user to make a change in the file called ChangeFile.txt. If not the application changes the last line in the file ChangeFile.txt, adds a new line and then posts its name in the file LastUserToMakeChanges.txt.

    Also due to issues with the try/catch in the timer catching errors, due to the app trying to open the file ChangeFile.txt while it was still in use by another process, the Timer1.Interval is auto incremented by 1 anytime an error is caught. This seems to be working well so far. All though I suppose it could become an issue if the timers interval was auto incremented to some drastic amount. But I'm running it right now and the timers interval on Alpha is now at 42 and Beta is at 34 which is a lot lower than 500 that I had them both set to in order not to get any errors. And they have been running for about 10 minutes now. Although there is also a Thread.Sleep of 200 between the time the file information that was changed is written into ChangeFile.txt and when the app posts its name in LastUserToMakeChanges.txt.

    I have a feeling the timers would be auto incrementing faster if all of the text from ChangeFile.txt was not being displayed in the RichTextBoxs constantly.

    "Alpha" code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Alpha"
            If File.Exists(Path1) = False Then
                Dim fs1 As FileStream = File.Create(Path1)
                fs1.Close()
                My.Computer.FileSystem.WriteAllText(Path1, "Alpha text to change" & vbCrLf, False)
            End If
            If File.Exists(Path2) = False Then
                Dim fs2 As FileStream = File.Create(Path2)
                fs2.Close()
                My.Computer.FileSystem.WriteAllText(Path2, "Alpha" & vbCrLf, False)
            End If
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine = "Alpha" Then
                    j += 1
                    Label1.Text = j.ToString
                    Exit Sub
                Else
                    System.Threading.Thread.Sleep(500)
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand.Next(0, 1000000000)))
                Label2.Text = ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Alpha text to change")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
    
                System.Threading.Thread.Sleep(200)
    
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Alpha")
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
            End Try
    
        End Sub
    
    End Class

    "Beta" code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Beta"
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine = "Beta" Then
                    j += 1
                    Label1.Text = j.ToString
                    Exit Sub
                Else
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
                Dim Rand As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand.Next(0, 1000000000)))
                Label2.Text = ChangedInfo(ChangedInfo.Count - 1)
    
            ChangedInfo.Add("Beta text to change")
    
            Dim sr3 As New System.IO.StreamWriter(Path1)
            If ChangedInfo.Count = 1 Then
                sr3.WriteLine(ChangedInfo(0))
            Else
                For i = 0 To ChangedInfo.Count - 1
                    sr3.WriteLine(ChangedInfo(i))
                Next
            End If
            sr3.Close()
    
            System.Threading.Thread.Sleep(200)
    
            Dim sr4 As New System.IO.StreamWriter(Path2)
            sr4.WriteLine("Beta")
            sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
            End Try
    
    
        End Sub
    
    End Class


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8




    Monday, June 24, 2013 10:16 AM
  • So I made it so 3 or more apps have access to work on the last line in ChangeFile.txt when a message from one of the other apps that added the last line into ChangeFile.txt lets the detecting apps know which one is their turn by the message posted in the LastUserToMakeChanges.txt file.

    Alpha code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
        Dim k As Integer = 1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Alpha"
            If File.Exists(Path1) = False Then
                Dim fs1 As FileStream = File.Create(Path1)
                fs1.Close()
                My.Computer.FileSystem.WriteAllText(Path1, "Alpha text to change" & vbCrLf, False)
            End If
            If File.Exists(Path2) = False Then
                Dim fs2 As FileStream = File.Create(Path2)
                fs2.Close()
                My.Computer.FileSystem.WriteAllText(Path2, "Alpha 2" & vbCrLf, False) ' Alpha 2 tells Beta to start the process
            End If
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine.Contains("Alpha") Or LUTMCLastLine.Contains("1") = False Then
                    j += 1
                    Label1.Text = "Detected for Alpha " & j.ToString & " times."
                    Exit Sub
                Else
                    System.Threading.Thread.Sleep(500)
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                    Label3.BackColor = Color.LimeGreen
                    j += 1
                    Label1.Text = "Detected for Alpha " & j.ToString & " times."
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand1 As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand1.Next(0, 1000)))
                Label2.Text = "Last msg processed = " & ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Alpha text")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
                Label5.Text = "Number of msgs processed = " & k.ToString
                k += 1
    
                System.Threading.Thread.Sleep(200)
    
                Dim Rand2 As New Random
                Dim PassOffTo As Integer = 0
                Do Until PassOffTo <> 1 AndAlso PassOffTo <> 0
                    PassOffTo = Rand2.Next(1, 4)
                Loop
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Alpha " & PassOffTo.ToString)
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Label3.BackColor = Color.OrangeRed
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
                j += 1
                Label1.Text = "Detected for Alpha " & j.ToString & " times."
            End Try
    
        End Sub
    
    End Class

    Beta code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
        Dim k As Integer = 1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Beta"
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine.Contains("Beta") Or LUTMCLastLine.Contains("2") = False Then
                    j += 1
                    Label1.Text = "Detected for Beta " & j.ToString & " times."
                    Exit Sub
                Else
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                    Label3.BackColor = Color.LimeGreen
                    j += 1
                    Label1.Text = "Detected for Beta " & j.ToString & " times."
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand1 As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand1.Next(0, 1000)))
                Label2.Text = "Last msg processed = " & ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Beta text")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
                Label5.Text = "Number of msgs processed = " & k.ToString
                k += 1
    
                System.Threading.Thread.Sleep(200)
    
                Dim Rand2 As New Random
                Dim PassOffTo As Integer = 0
                Do Until PassOffTo <> 2 AndAlso PassOffTo <> 0
                    PassOffTo = Rand2.Next(1, 4)
                Loop
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Beta " & PassOffTo.ToString)
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Label3.BackColor = Color.OrangeRed
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
                j += 1
                Label1.Text = "Detected for Beta " & j.ToString & " times."
            End Try
    
        End Sub
    
    End Class
    

    Gamma code

    Option Strict On
    
    Imports System.IO
    
    Public Class Form1
    
        ' http://social.msdn.microsoft.com/Forums/en-US/31609ee6-5d0a-4a51-a275-77bc32e25c10/file-system-watcher-who-wrote-into-the-file
    
        Dim Path1 As String = "C:\Users\John\Desktop\Test Folder\ChangeFile.txt"
        Dim Path2 As String = "C:\Users\John\Desktop\Test Folder\LastUserToMakeChanges.txt"
    
        Dim CFLastLine As String = ""
        Dim LUTMCLastLine As String = ""
        Dim AddText As String = ""
    
        Dim ChangedInfo As New List(Of String)
    
        Dim j As Integer = 0
        Dim k As Integer = 1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.Text = "Gamma"
            Timer1.Interval = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Timer1.Stop()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Try
                RichTextBox1.Text = ""
                ChangedInfo.Clear()
                Dim LastLine As String = ""
                Dim sr1 As New System.IO.StreamReader(Path2)
    
                Do While sr1.Peek() <> -1
                    LUTMCLastLine = sr1.ReadLine()
                Loop
                sr1.Close()
    
                If LUTMCLastLine.Contains("Gamma") Or LUTMCLastLine.Contains("3") = False Then
                    j += 1
                    Label1.Text = "Detected for Gamma " & j.ToString & " times."
                    Exit Sub
                Else
                    Dim sr2 As New System.IO.StreamReader(Path1)
                    Do While sr2.Peek() <> -1
                        ChangedInfo.Add(sr2.ReadLine())
                    Loop
                    sr2.Close()
                    Label3.Text = ""
                    Label3.BackColor = Color.LimeGreen
                    j += 1
                    Label1.Text = "Detected for Gamma " & j.ToString & " times."
                End If
    
                For Each Item In ChangedInfo
                    RichTextBox1.AppendText(Item & vbCrLf)
                Next
                RichTextBox1.ScrollToCaret()
    
                Dim Rand1 As New Random
                ChangedInfo(ChangedInfo.Count - 1) = ChangedInfo(ChangedInfo.Count - 1).Insert(0, CStr(Rand1.Next(0, 1000)))
                Label2.Text = "Last msg processed = " & ChangedInfo(ChangedInfo.Count - 1)
    
                ChangedInfo.Add("Gamma text")
    
                Dim sr3 As New System.IO.StreamWriter(Path1)
                If ChangedInfo.Count = 1 Then
                    sr3.WriteLine(ChangedInfo(0))
                Else
                    For i = 0 To ChangedInfo.Count - 1
                        sr3.WriteLine(ChangedInfo(i))
                    Next
                End If
                sr3.Close()
                Label5.Text = "Number of msgs processed = " & k.ToString
                k += 1
    
                System.Threading.Thread.Sleep(200)
    
                Dim Rand2 As New Random
                Dim PassOffTo As Integer = 0
                Do Until PassOffTo <> 3 AndAlso PassOffTo <> 0
                    PassOffTo = Rand2.Next(1, 4)
                Loop
                Dim sr4 As New System.IO.StreamWriter(Path2)
                sr4.WriteLine("Gamma " & PassOffTo.ToString)
                sr4.Close()
            Catch ex As Exception
                Label3.Text = ex.Message
                Label3.BackColor = Color.OrangeRed
                Timer1.Interval += 1
                Label4.Text = "Timer1.Interval = " & CStr(Timer1.Interval)
                j += 1
                Label1.Text = "Detected for Gamma " & j.ToString & " times."
            End Try
    
        End Sub
    
    End Class
    


    You've taught me everything I know but not everything you know. _________________________________________________________________________________________________________________ This search engine is for MSDN Library and has many features. http://social.msdn.microsoft.com/Search/en-US?query=search%20msdn%20library&beta=0&ac=8

    Monday, June 24, 2013 8:55 PM
  • Hi Ha3R,

    I believe you'll have to use some combination of what the others have already shown you, mostly depending on how you need your data file formatted.  You could concatenate values within one file or use multiple files to store different aspects of each transaction. But regardless of how you decide to share the data file, the simplest way to prevent multiple user contention issues is to use a lock file.

    Before your application attempts to open the shared data file, it first tries to create a lock file with a specific file name and/or extension, using a File Create method which does not allow overwriting an existing file.  This lock file can be a zero byte file, or it might contain a small amount of data pertaining to the user who took the lock.

    Since the application is attempting to create the lock file without overwrite permission, and every instance of the application will attempt to create the same lock file name, an exception will occur if the lock file already exists and you can catch this to indicate that the file is already in use by another program.  Even if two or more instances attempt to take a lock at the same time, only the first to be processed by Windows can succeed and the others must fail.

    After the application is done editing the data file, it can delete the lock file that it created.

    The downside is that this method becomes inefficient quickly if there are many frequent changes to the data file.  But if the changes tend to come sporadically from various clients without any one heavy load then it may work just fine.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Monday, June 24, 2013 9:59 PM