Members

Technology Zones

IBM Learning Center

Articles

Hosted By

MaximumASP

Info

[3636] Watching Folder Activity in VB.NET

Last post 02-06-2008 12:28 AM by D'Scouser. 14 replies.
Page 1 of 1 (15 items)
Sort Posts: Previous Next
  • 01-01-1999 12:00 AM

    [3636] Watching Folder Activity in VB.NET

    This thread is for discussions of Watching Folder Activity in VB.NET.

    • Post Points: 0
  • Advertisement

    • Red Gate Software

    Advertisement

    Want to boost your .NET application performance?

    Some developers always seem to write efficient and lightening-fast code. What is their secret? It’s ANTS Profiler. “We improved the performance of the application up to 10 times” Dan Ports, Intrigma.

    Try it for yourself now.

  • 08-04-2003 10:02 AM In reply to

    Use as a windows service?

    Never mind, figured it out!
    • Post Points: 0
  • 09-25-2003 4:27 PM In reply to

    • jsohrt
    • Not Ranked
    • Joined on 09-25-2003
    • New Member
    • Points 5

    Work across mapped or unc drives?

    I'm using the filewatcher and it seems to only raise events when file/dir changes occur on the local C drive.  I'm using Win Xp Pro.  I've tried to have it watch drives across the network using both mapped (Z:) and UNC (//servername/dir) and no events get raised.

    The computer I'm trying to watch is a Windows 2000 O.S.  Mine is xp pro.  

    Should this work or not?

    Thanks
    jds
    • Post Points: 0
  • 10-17-2003 10:47 AM In reply to

    • rbhatia
    • Not Ranked
    • Joined on 10-17-2003
    • New Member
    • Points 10

    Who read the file

    Hi. Truly loved the article ! Would like to know however, how I could also view the person who accessed or changed the file. If this application were to run on a Windows 2000 box that is part of a Windows 2000 domain, would it be possible to output the NT account that accessed the file ?
    Also, I assume that the file change state would accomodate a file read so if somebody were to simply open a file to read and close without making any changes, shouldn't that raise the File Changed event ? Apparently this does not happen in my case.
    Please advise.
    Thanks
    • Post Points: 0
  • 02-09-2004 8:48 AM In reply to

    • aziliat
    • Not Ranked
    • Joined on 02-09-2004
    • New Member
    • Points 10

    how to make this into windows service

    I like the code and it works well as a regular windows app.
    But I am trying to make it into a Windows service and I keep getting a System.IO.FileNotFoundException.

    How do I alter the security so the system can see the directories?

    The code fails on the following line:

    WatchedFolder.Path = DistillerPath

    I tried to see if the path exists first, but this always returns false
    System.IO.Directory.Exists(DistillerPath)

    Thanks.
    • Post Points: 0
  • 03-16-2004 5:10 AM In reply to

    • gio_dim
    • Not Ranked
    • Joined on 03-16-2004
    • New Member
    • Points 5
    Imports System.IO
    Imports System.Diagnostics
    Imports System.ServiceProcess

    Public Class Service1
       Inherits System.ServiceProcess.ServiceBase
       Public watchfolder As FileSystemWatcher
    #Region " Component Designer generated code "

       Public Sub New()
           MyBase.New()

           ' This call is required by the Component Designer.
           InitializeComponent()

           ' Add any initialization after the InitializeComponent() call

       End Sub

       'UserService overrides dispose to clean up the component list.
       Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
           If disposing Then
               If Not (components Is Nothing) Then
                   components.Dispose()
               End If
           End If
           MyBase.Dispose(disposing)
       End Sub

       ' The main entry point for the process
       <MTAThread()> _
       Shared Sub Main()
           Dim ServicesToRun() As System.ServiceProcess.ServiceBase

           ' More than one NT Service may run within the same process. To add
           ' another service to this process, change the following line to
           ' create a second service object. For example,
           '
           '   ServicesToRun = New System.ServiceProcess.ServiceBase () {New Service1, New MySecondUserService}
           '
           ServicesToRun = New System.ServiceProcess.ServiceBase() {New Service1}

           System.ServiceProcess.ServiceBase.Run(ServicesToRun)
       End Sub

       'Required by the Component Designer
       Private components As System.ComponentModel.IContainer

       ' NOTE: The following procedure is required by the Component Designer
       ' It can be modified using the Component Designer.  
       ' Do not modify it using the code editor.
       Friend WithEvents Timer1 As System.Windows.Forms.Timer
       <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
           Me.components = New System.ComponentModel.Container
           Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
           '
           'Timer1
           '
           Me.Timer1.Enabled = True
           Me.Timer1.Interval = 1
           '
           'Service1
           '
           Me.ServiceName = "Service1"

       End Sub

    #End Region
       Public Function StopWatch()
           watchfolder.EnableRaisingEvents = False
           WriteToFile("Service Stopped.")
       End Function
       Public Function StartWatch()
           ' Add code here to start your service. This method should set things
           ' in motion so your service can do its work.
           WriteToFile("Setting Folder to watch... ")
           watchfolder = New System.IO.FileSystemWatcher("C:\mypath")
           WriteToFile("""" & watchfolder.Path & """" & vbNewLine & "Done" & vbNewLine)

           'this is the path we want to monitor
           'watchfolder.Path = "C:\mypath"

           '        watchfolder.Path = txt_watchpath.Text

           'Add a list of Filter we want to specify
           'make sure you use OR for each Filter as we need to
           'all of those
           'WriteToFile("01")

           watchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
           watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
           IO.NotifyFilters.FileName
           watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
           IO.NotifyFilters.Attributes

           ' add the handler to each event
           AddHandler watchfolder.Changed, AddressOf logchange
           AddHandler watchfolder.Created, AddressOf logchange
           AddHandler watchfolder.Deleted, AddressOf logchange

           ' add the rename handler as the signature is different
           AddHandler watchfolder.Renamed, AddressOf logrename

           'Set this property to true to start watching
           watchfolder.EnableRaisingEvents = True

           'End of code for btn_start_click
       End Function

       Public Function WriteToFile(ByVal pr_String As String)
           FileOpen(1, "C:\temp\Log.log", OpenMode.Append)
           Print(1, pr_String)
           pr_String = ""
           FileClose(1)
       End Function
       Public Sub logrename(ByVal source As Object, ByVal e As System.IO.RenamedEventArgs)
           WriteToFile("File" & e.OldName & " has been renamed to " & e.Name & vbCrLf)
           'txt_folderactivity.Text &= "File" & e.OldName & _
           '" has been renamed to " & e.Name & vbCrLf
       End Sub

       Private Sub logchange(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
           If e.ChangeType = IO.WatcherChangeTypes.Changed Then
               WriteToFile("File " & e.FullPath & " has been modified" & vbCrLf)
               'txt_folderactivity.Text &= "File " & e.FullPath & _
               '" has been modified" & vbCrLf
           End If
           If e.ChangeType = IO.WatcherChangeTypes.Created Then
               WriteToFile("File " & e.FullPath & " has been created" & vbCrLf)
               'txt_folderactivity.Text &= "File " & e.FullPath & _
               '" has been created" & vbCrLf
           End If
           If e.ChangeType = IO.WatcherChangeTypes.Deleted Then
               WriteToFile("File " & e.FullPath & " has been deleted" & vbCrLf)
               'txt_folderactivity.Text &= "File " & e.FullPath & _
               '" has been deleted" & vbCrLf
           End If
       End Sub

       Protected Overrides Sub OnStart(ByVal args() As String)
           ' Add code h
    • Post Points: 0
  • 06-10-2005 1:52 PM In reply to

    • pjay23
    • Not Ranked
    • Joined on 06-10-2005
    • New Member
    • Points 20

    i want to perform a action when a file is generate

    i liked the folder watch very much... to use it more appropriately i just wanted to implement to unzip files once a folder receives any kind of zip files ...

    i tried

    Private Sub logchange(ByVal source As Object, ByVal e As _
    System.IO.FileSystemEventArgs)
           If e.ChangeType = IO.WatcherChangeTypes.Changed Then
               txt_folderactivity.Text &= "File " & e.FullPath & _
               " has been modified" & vbCrLf
               ExecuteApplication("C:\WinRAR\WinRAR.exe x <source> <destn>
           End If
           If e.ChangeType = IO.WatcherChangeTypes.Created Then
               txt_folderactivity.Text &= "File " & e.FullPath & _
               " has been created" & vbCrLf
               ExecuteApplication("C:\WinRAR\WinRAR.exe x <source> <destn>

           End If
           If e.ChangeType = IO.WatcherChangeTypes.Deleted Then
               txt_folderactivity.Text &= "File " & e.FullPath & _
               " has been deleted" & vbCrLf
               ExecuteApplication("C:\WinRAR\WinRAR.exe x <source> <destn>

           End If
       End Sub
       Public Sub ExecuteApplication(ByVal pstrApplicationName As String)
           Dim udtProcess As Process = New Process
           udtProcess.Start(pstrApplicationName)
           udtProcess.Close()

       End Sub

    It doesnt work ... it opens the winrar and hangs up....

    where do i go wrong in giving the command line syntax for unzipping ... and one more thing is it opens the winrar application which i think should work in the background like it does when i paste the command in START->RUN

    thanks in anticipation Jayesh
    • Post Points: 0
  • 06-24-2005 3:12 PM In reply to

    • vikramp
    • Not Ranked
    • Joined on 06-24-2005
    • New Member
    • Points 10

    How to make sure file is created properly

    Hi,

    This is wonderful article. I used it to write a small utility... kinda backup utility.

    I have one problem though:

    To test the application, I copied a big file (about 100 MB in size) from another folder on my computer, to the folder I was watching. It took few seconds to copy this 100 MB file to the watch folder.
    However, my program tried to access this file immediately (while copying was not yet finished). So my program threw an exception saying the File is being used by another program.

    How to make sure that the new file has been properly created in the watch folder before trying to access it?
    (so in my case, I want my program to access this file only after it is completely copied to the watch folder)


    Thanks in advance,

    Vikram
    • Post Points: 0
  • 07-07-2005 1:43 AM In reply to

    • jmurdock
    • Not Ranked
    • Joined on 07-07-2005
    • New Member
    • Points 10

    Can't read the file...

    I am working on an application to use the filewatcher (this is a windows service) to recognize when an xml file is placed in a directory, it is then to read the file and use it.

    When ever I try to read the file I get the error that the file is in use. Since it isn't, I have to assume that the file watcher has somehow locked the file and I cannot open it.

    How do I make the file watcher 'let go'???
    • Post Points: 0
  • 07-12-2005 5:14 PM In reply to

    What are you doing with your service? I need the same type of thing but I need to parse the xml and sent it to SQL server. I have done this in vbscript not a problem but I cannot seem to get it to work in VB.net I get cross thread errors. jwillis27640@troy.edu
    • Post Points: 0
  • 07-12-2005 5:44 PM In reply to

    • jmurdock
    • Not Ranked
    • Joined on 07-07-2005
    • New Member
    • Points 10
    Quote:
    [1]Posted by jwillis27640 on 12 Jul 2005 05:14 PM[/1]
    What are you doing with your service? I need the same type of thing but I need to parse the xml and sent it to SQL server. I have done this in vbscript not a problem but I cannot seem to get it to work in VB.net I get cross thread errors. jwillis27640@troy.edu


    I am doing exactly what you are doing. I resolved my file locked issue by doing this:

    <code>

    Do While IO.File.GetAttributes(strFileName) = FileAttributes.Offline
                           'Wait 1/2 second before trying again.
                           Threading.Thread.Sleep(500)
                       Loop
                       Threading.Thread.Sleep(500)
                       fnReadXML(strFileName)
    </code>

    fnReadXML works like this:

    <code>

    Function fnReadXML(ByVal strFileName As String)

           Dim fStream As New FileStream(strFileName, FileMode.Open)
           Dim reader As XmlTextReader = New XmlTextReader(fStream)
           Dim dsPO As New DataSet
           Dim cError As New CustomError
           Dim cErrors As CustomError()

           Try
               dsPO.ReadXml(reader)
               reader.Close()
               fStream.Close()

               'Data Set has 2 tables, form relationship.
               fnMakeRelationship(dsPO)

               'Now that there is a dataset, use it to do my insert into SQL. Return errors if there are any.
               cErrors = fnInsertPOFromDS(dsPO, strFileName)

           Catch ex As Exception
               EventLog.WriteEntry(Me.ServiceName, Me.ServiceName & " XMLTextReader " & ex.ToString, EventLogEntryType.Error)
           End Try

           reader = Nothing
           dsPO.Dispose()
           File.Delete(strFileName)

    </code>
    • Post Points: 10
  • 07-12-2005 11:44 PM In reply to

    Thanks JMurDock!! Maybe you can help me with this. I am using Excel 2003 to parse the XML because I don't know what information might be in the file. It has varying field information so I do it like this in vbscript:

    I am sorry I am kind of a newbie!!  Is there a way to use a recordset in the same way and pass the information to addRecords as arrays?

    My last question is really stupid but here goes... Is there a way not to have to use ODBC and use a provider instead?

    <code>

    '************************************************
    Sub ParseXML(strFileName)


    Set objExcel = CreateObject("Excel.Application")
    objExcel.Visible = False
    Set objWorkbook = objExcel.Workbooks.Open(strFileName)
    strValue = ""

    col = 1
    row = (-2)

    x = 1 'Excel
    z = 1 'Excel
    w = 2
    y = 1


    Do Until objExcel.Cells(x,1).Value = ""
       row = row + 1
       x = x + 1
    Loop

    Do Until objExcel.Cells(2,x).Value = ""
       x = x + 1
       col = x
    Loop


    ReDim rowHeader((col - 1))
    x = 2
    z = 0

    for x = 2 to 2
     
     

     for y = 1 to col
     
     strValue = objExcel.Cells(x,y).Value
     

     rowHeader(y-1) = RTRIM(strValue)
     
     'Collect Row Header Data Here
     
     next
     

    next
    x = x + 1



    x = 3



    for x = 3 to (row + 2)
     

     ReDim rowArr((col - 1))  
     
     for y = 1 to col
     
     rowArr(y-1) = objExcel.Cells(x,y).Value


    'Collect Row Data Here


     next
     'y = y + 1


    'Database Insert Here!

    AddRecords rowHeader, rowArr

    next
    x = x + 1

    objExcel.quit
    End Sub
    '************************************************




    '************************************************
    Sub AddRecords(strheader, strrowdata)

    On Error Resume Next
    i = 0
    j = (UBound(strheader) - 1)


    Const adOpenStatic = 3
    Const adLockOptimistic = 3
    Const adUseClient = 3
    Set objConnection = CreateObject("ADODB.Connection")
    Set objRecordset = CreateObject("ADODB.Recordset")
    objConnection.Open "DSN=S795A54;UID=XXXX;pwd=XXXX"
    objRecordset.CursorLocation = adUseClient
    objRecordset.Open "FECS" , objConnection, _
       adOpenStatic, adLockOptimistic

    i = 0 ' reset counter to zero
    objRecordset.AddNew
       for i = 0 to j
       objRecordset(strHeader(i)) = strrowdata(i) 'strRecords(i)
       Next
       'i = i + 1
       objRecordset("DOCUMENT") = "\\" & strComputer & "\dma\fecs\tiffs"
       objRecordset("FUNCADDDATE") = now()
       objRecordset.Update

    objRecordset.Close
    objConnection.Close

    End Sub
    '************************************************


    </code>
    • Post Points: 0
  • 09-26-2005 4:42 PM In reply to

    • tlombardi
    • Not Ranked
    • Joined on 09-26-2005
    • United States
    • New Member
    • Points 5

    Running this code as a service

    Hi I have tried this code to use it for watching a folder for tif files which I wish to print automatically. I have managed to get it to work in an application mode. However I cant seem to make it work as a service.

    I have included eventlog entries in the found new file handlers however nothing gets logged to the eventlog.

    below is the code: where have i gone wrong?

    Imports System.io
    Imports System.IO.FileSystemWatcher
    Imports System.diagnostics
    Imports System.Drawing.Printing
    Imports System.ServiceProcess

    Public Class folderWatch
       Inherits System.ServiceProcess.ServiceBase
       Public VARwatchfolder As FileSystemWatcher
       Public mapImage As System.Drawing.Bitmap
       Dim folderToWatch As String = "C:\folderWatchTest"


    #Region " Component Designer generated code "

       Public Sub New()
           MyBase.New()

           ' This call is required by the Component Designer.
           InitializeComponent()

           ' Add any initialization after the InitializeComponent() call

       End Sub

       'UserService overrides dispose to clean up the component list.
       Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
           If disposing Then
               If Not (components Is Nothing) Then
                   components.Dispose()
               End If
           End If
           MyBase.Dispose(disposing)
       End Sub

       ' The main entry point for the process
       <MTAThread()> _
       Shared Sub Main()
           Dim ServicesToRun() As System.ServiceProcess.ServiceBase

           ' More than one NT Service may run within the same process. To add
           ' another service to this process, change the following line to
           ' create a second service object. For example,
           '
           '   ServicesToRun = New System.ServiceProcess.ServiceBase () {New folderWatch, New MySecondUserService}
           '
           ServicesToRun = New System.ServiceProcess.ServiceBase() {New folderWatch}

           System.ServiceProcess.ServiceBase.Run(ServicesToRun)
       End Sub

       'Required by the Component Designer
       Private components As System.ComponentModel.IContainer

       ' NOTE: The following procedure is required by the Component Designer
       ' It can be modified using the Component Designer.  
       ' Do not modify it using the code editor.
       Friend WithEvents Timer1 As System.Windows.Forms.Timer
       <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
           Me.components = New System.ComponentModel.Container
           Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
           '
           'Timer1
           '
           Me.Timer1.Enabled = True
           Me.Timer1.Interval = 1
           '
           'folderWatch
           '
           Me.ServiceName = "folderWatch"

       End Sub

    #End Region

       Protected Overrides Sub OnStart(ByVal args() As String)
           ' Add code here to start your service. This method should set things
           ' in motion so your service can do its work.

           folderWatch()
           System.Diagnostics.EventLog.WriteEntry("folderWatch", "FolderWatch service started!!! watching folder: " & folderToWatch)


       End Sub

       Protected Overrides Sub OnStop()
           ' Add code here to perform any tear-down necessary to stop your service.
           VARwatchfolder.EnableRaisingEvents = False


       End Sub

       Public Function folderWatch()
           'System.Diagnostics.EventLog.WriteEntry("folderWatch", "folderWatch Subroutine starts here")
           'monitorTimer.Start()
           
           VARwatchfolder = New System.IO.FileSystemWatcher

           VARwatchfolder.Path = folderToWatch
           VARwatchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
           VARwatchfolder.NotifyFilter = VARwatchfolder.NotifyFilter Or _
           IO.NotifyFilters.FileName
           VARwatchfolder.NotifyFilter = VARwatchfolder.NotifyFilter Or _
           IO.NotifyFilters.Attributes
           'VARwatchfolder.Filter = "*.tif"

           AddHandler VARwatchfolder.Created, AddressOf logCreate
           AddHandler VARwatchfolder.Changed, AddressOf logCreate

           VARwatchfolder.EnableRaisingEvents = True




       End Function
       Private Sub logCreate(ByVal Source As Object, ByVal e As System.IO.FileSystemEventArgs)
           If e.ChangeType = IO.WatcherChangeTypes.Changed Then
               System.Diagnostics.EventLog.WriteEntry("folderWatch_change", "Found change in file: " & e.FullPath)
           End If
           If e.ChangeType = IO.WatcherChangeTypes.Created Then

               System.Diagnostics.EventLog.WriteEntry("folderWatch_new", "Found New file: " & e.FullPath)

               Dim imageFile As New System.Drawing.Bitmap(e.FullPath)
               mapImage = imageFile
               Dim printer As String = PrinterSettings.InstalledPrinters.Item(0)
               Dim pd As New PrintDocument
               AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage

               pd.Print()
               mapImage.Dispose()
               System.Diagnostics.EventLog.WriteEntry("folderWatch_print", "Printed New file: " & e.FullPath)


               Dim printedFilesPath As String
               printedFilesPath = Replace(e.FullPath, folderToWatch, folderToWatch & "\printed")
               '                If CBmoveAfterPrint.Checked = True Then
               System.IO.File.Move(e.FullPath, printedFilesPath)
               System.Diagnostics.EventLog.WriteEntry("folderWatch", "will move file to " & printedFilesPath)
               '   &
    • Post Points: 0
  • 12-04-2005 6:51 PM In reply to

    • wduros1
    • Not Ranked
    • Joined on 12-04-2005
    • New Member
    • Points 10

    One way...

    Although the file watcher provides notification of a file create, it provides this notification at the moment of the file "creation", not the moment of the file "completion" if you know what I mean.  If I create a file, then wait two minutes and write data into the file, then wait another two minutes and close the file,  file watch will fire the create event on the file create, not four minutes after, when the file is closed.  Even worse, if you create the file but close it.  The later open it and write data and close.

    This is an old problem with watching for files.  The question "How do I know that the file is finished creating?"  has the same answer as "How do I know the cake is finished baking?".    You can time it, check it, and when you think it's done try to eat it, if it's not done, put it back in the oven...

    What I usually do is add the file path and file size to a list, and then wait a period of time.  When the time has elapsed, I compare the current file size against the earlier file size.  When the file size has not changed for two subsequent checks, I "Assume" the file is done.  

    This method is, of course, flawed, since a network outage, or a slow connection, or an Application that writes in stages, etc. etc. could break it.  I wish that there was a more definitive way to know.  The secret to making this work in all conditions is to be able to spit the file back out if it's not "done".   (Try to eat the cake, and if it's not done, put it back in the oven and continue to wait.)

    • Post Points: 0
  • 02-06-2008 12:28 AM In reply to

    • D'Scouser
    • Top 150 Contributor
    • Joined on 09-20-2007
    • United Kingdom
    • Fanatic Member
    • Points 1,015

    Re: Cross-Threading

    In VB2005 there is a painful cross-threading error that throws an InvalidOperationException when returning text from the fileSystemWatcher to the main form. This can be resolved by declaring a Delegate and adding a Sub routine to handle the cross-threading issue on the txtFolderActivity textbox.

    Private Sub CheckCrossThread(ByVal message As String)
    If Me.txtFolderActivity.InvokeRequired Then
    Dim cct As New SetTextCallback(AddressOf CheckCrossThread) Me.Invoke(cct, New Object() {message})
    Else Me.txtFolderActivity.Text = message

    You then just put the code in the logChange/Renamed sub int the CheckCrossThread routine.

    • Post Points: 5
Page 1 of 1 (15 items)