?
Solved

wait until file has completed transfer before command runs on hotfolder

Posted on 2010-01-11
26
Medium Priority
?
670 Views
Last Modified: 2012-05-08
I have this code working just fine with smaller files, but since I will be working with multiple files and files in the 1GB to 1.5 GB range it doesn't work for what I need.

How can I get this code to wait until the file is done transferring to the hot folder before attempting to run the commands?
Imports System.IO

Public Class Form1
    Inherits System.Windows.Forms.Form
    Public Function ExecCommand(ByRef CommandLine As String, _
                            Optional ByRef Arguments As String = "", _
                            Optional ByRef Waitforexit As Boolean = True) As Integer
        Dim psi As New ProcessStartInfo()
        Dim p As Process

        With psi
            .FileName = CommandLine
            .Arguments = Arguments
            .WindowStyle = ProcessWindowStyle.Hidden 'This avoid a text window being opened
        End With
        Try
            p = Process.Start(psi) 'This line runs the command
            If Waitforexit Then p.WaitForExit() 'This wait until the command ends
            Return p.ExitCode
        Catch e As System.Exception
            'Catch errors here
        End Try
    End Function

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

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

        'Add any initialization after the InitializeComponent() call

    End Sub

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

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

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents lstFiles As System.Windows.Forms.ListBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.lstFiles = New System.Windows.Forms.ListBox
        Me.SuspendLayout()
        '
        'lstFiles
        '
        Me.lstFiles.Dock = System.Windows.Forms.DockStyle.Fill
        Me.lstFiles.Location = New System.Drawing.Point(0, 0)
        Me.lstFiles.Name = "lstFiles"
        Me.lstFiles.Size = New System.Drawing.Size(1025, 368)
        Me.lstFiles.TabIndex = 0
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(1025, 372)
        Me.Controls.Add(Me.lstFiles)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private m_WatchDirectory As String
    Private WithEvents m_FileSystemWatcher As FileSystemWatcher

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'lstFiles.Items.Add(Now.ToString() & " Starting")

        ' Get the path to the directory we will watch.
        'm_WatchDirectory = Application.StartupPath
        'm_WatchDirectory = m_WatchDirectory.Substring(0, m_WatchDirectory.LastIndexOf("\"))
        m_WatchDirectory &= "c:\docume~1\user\desktop\howtofolderwatcher\baton\bad"

        ' Make the FileSystemWatcher.
        m_FileSystemWatcher = New FileSystemWatcher(m_WatchDirectory, "*.mpg")
        m_FileSystemWatcher.NotifyFilter = 0
        m_FileSystemWatcher.NotifyFilter = m_FileSystemWatcher.NotifyFilter Or NotifyFilters.FileName
        m_FileSystemWatcher.EnableRaisingEvents = True

        ' Process any files that already exist.
        'ProcessExistingFiles(m_WatchDirectory)
    End Sub

    ' Process a new file.
    Private Sub m_FileSystemWatcher_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles m_FileSystemWatcher.Created
        ProcessFile(e.Name)
    End Sub

    ' Process existing files.
    'Private Sub ProcessExistingFiles(ByVal directory_name As String)
    'Dim dir_info As New DirectoryInfo(directory_name)
    'Dim file_infos As FileInfo() = dir_info.GetFiles()
    'For Each fi As FileInfo In file_infos
    'ProcessFile(fi.FullName)
    'Next fi
    ' End Sub

    ' Process a file.
    Private Delegate Sub mProcessFileDelegate(ByVal file_name As String)

    Private Sub ProcessFile(ByVal file_name As String)

        If lstFiles.InvokeRequired Then

            Dim d As New mProcessFileDelegate(AddressOf ProcessFile)
            lstFiles.Invoke(d, New Object() {file_name})

        Else


            'ExecCommand...
            ExecCommand("cmd", " /c " & "c:\docume~1\user\desktop\howtofolderwatcher\baton\bad\dtrmxutil.exe " & "c:\docume~1\user\desktop\howtofolderwatcher\baton\bad\" & file_name & " c:\docume~1\marc.viste\desktop\howtofolderwatcher\baton\bad\nulls\" & file_name & " 6000000", Waitforexit:=True)
            lstFiles.Items.Add(Now.ToString() & " Processed " & file_name)
        End If


    End Sub





End Class

Open in new window

0
Comment
Question by:cpservice
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
26 Comments
 
LVL 13

Expert Comment

by:zadeveloper
ID: 26288592
try adding

Public Function ExecCommand(ByRef CommandLine As String, _
                            Optional ByRef Arguments As String = "", _
                            Optional ByRef Waitforexit As Boolean = True) As Integer
        Dim psi As New ProcessStartInfo()
        Dim p As Process

        With psi
            .FileName = CommandLine
            .Arguments = Arguments
            .WindowStyle = ProcessWindowStyle.Hidden 'This avoid a text window being opened
        End With
        Try
            p = Process.Start(psi) 'This line runs the command
            If Waitforexit Then p.WaitForExit() 'This wait until the command ends

            While Not p.HasExited
                System.Windows.Forms.Application.DoEvents()
            End While

            Return p.ExitCode
        Catch e As System.Exception
            'Catch errors here
        End Try
    End Function

Open in new window

0
 

Author Comment

by:cpservice
ID: 26288680
If I copy the file over it is the same result. The file is in use due to not being done transferring and the command fails.
0
 

Author Comment

by:cpservice
ID: 26288776
Small files and instant transfer like a cut and paste on the same storage array/hard drive seems to work just fine. So at this point we still need to work out how to make the application wait until the files have completed transferring before it runs the commands.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 11

Expert Comment

by:lenordiste
ID: 26288855
you could use the BackgroundWorker class and start retrieving your files asynchronously. You then only have to wait for the backgroundworker to raise its "OnRunWorkerCompleted " event to make sure the file is done transfering.

here is a place to start:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26288858
This is a common problem with FileSystemWatchers type applications.

One solution is to add the FileName to a List and then simply keep trying again periodically with a Timer control (use a fairly SLOW interval like 5 seconds) until you don't get an exception.  Once success has been achieved you remove the FileName from the "working" list...
0
 

Author Comment

by:cpservice
ID: 26288926
I have been piecing this together with help from others as yourselves, so both of these options sound good, but I don't know how to implement them. The second option sounds like the simpler one to be honest.

Would it be easier to use a listbox and make it invisible somehow or actually write to a text file?
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26288950
What version VB.Net are you working with?   (looks like 2003 but I want to make sure)
0
 

Author Comment

by:cpservice
ID: 26288955
vb.net 2008 express is what I am using and part of the code is updated from vb6
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 26289598
I would vote for the exception handling.

Example:


Imports System.IO
Imports System.Xml

Public Class Form1

    Private WithEvents m_FileSystemWatcher As FileSystemWatcher

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        m_FileSystemWatcher = New FileSystemWatcher("c:\temp", "*.mp3")
        m_FileSystemWatcher.NotifyFilter = 0
        m_FileSystemWatcher.NotifyFilter = m_FileSystemWatcher.NotifyFilter Or NotifyFilters.FileName
        m_FileSystemWatcher.EnableRaisingEvents = True
    End Sub

    Private Sub m_FileSystemWatcher_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles m_FileSystemWatcher.Created
        Dim isDeleted As Boolean
        While Not isDeleted
            Try
                File.Delete(e.FullPath)
                isDeleted = True
            Catch ex As Exception
            End Try
        End While

    End Sub

End Class

Open in new window

0
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 2000 total points
ID: 26290103
Or try this out:
Imports System.IO
Public Class Form1

    Public Class Files
        Public Shared ToBeProcessed As New Queue(Of String)
        Public Shared SharedObject As New Object
        Public Shared MRE As New System.Threading.ManualResetEvent(False)
    End Class

    Private m_WatchDirectory As String
    Private WithEvents m_FileSystemWatcher As FileSystemWatcher
    Private WithEvents bgw As New System.ComponentModel.BackgroundWorker

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        bgw.WorkerReportsProgress = True
        bgw.RunWorkerAsync()

        m_WatchDirectory &= "c:\docume~1\user\desktop\howtofolderwatcher\baton\bad"

        ' Make the FileSystemWatcher.
        m_FileSystemWatcher = New FileSystemWatcher(m_WatchDirectory, "*.mpg")
        m_FileSystemWatcher.NotifyFilter = 0
        m_FileSystemWatcher.NotifyFilter = m_FileSystemWatcher.NotifyFilter Or NotifyFilters.FileName
        m_FileSystemWatcher.EnableRaisingEvents = True
    End Sub

    ' Process a new file.
    Private Sub m_FileSystemWatcher_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles m_FileSystemWatcher.Created
        SyncLock Files.SharedObject
            If Not Files.ToBeProcessed.Contains(e.Name) Then
                Files.ToBeProcessed.Enqueue(e.Name)
                Files.MRE.Set()
            End If
        End SyncLock
    End Sub

    Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
        Dim FileName As String
        Dim HasMoreItems As Boolean
        While True
            Files.MRE.Reset()
            HasMoreItems = False
            Do
                Filename = Nothing
                SyncLock Files.SharedObject
                    If Files.ToBeProcessed.Count > 0 Then
                        FileName = Files.ToBeProcessed.Peek
                    End If
                End SyncLock

                If Not IsNothing(FileName) Then
                    Dim P As New Process
                    P.StartInfo.FileName = "cmd"
                    P.StartInfo.Arguments = "/c " & "c:\docume~1\user\desktop\howtofolderwatcher\baton\bad\dtrmxutil.exe " & "c:\docume~1\user\desktop\howtofolderwatcher\baton\bad\" & FileName & " c:\docume~1\marc.viste\desktop\howtofolderwatcher\baton\bad\nulls\" & FileName & " 6000000"
                    Try
                        P.Start()
                        P.WaitForExit()
                        SyncLock Files.SharedObject
                            Files.ToBeProcessed.Dequeue()
                        End SyncLock
                        bgw.ReportProgress(0, FileName)
                    Catch ex As Exception
                        System.Threading.Thread.Sleep(5000) ' wait 5 seconds before trying again
                    End Try
                End If

                SyncLock Files.SharedObject
                    HasMoreItems = (Files.ToBeProcessed.Count > 0)
                End SyncLock
            Loop While HasMoreItems
            Files.MRE.WaitOne()
        End While
    End Sub

    Private Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw.ProgressChanged
        lstFiles.Items.Add(Now.ToString() & " Processed " & e.UserState)
    End Sub

End Class

Open in new window

0
 
LVL 12

Expert Comment

by:rajapandian_81
ID: 26292695
0
 

Author Comment

by:cpservice
ID: 26293977
With the second solution I get the following errors:

Error      1      'Sub Main' was not found in 'howto_net_filesystemwatcher.Form1'.      howto_net_filesystemwatcher
Error      2      'System.Collections.Queue' has no type parameters and so cannot have type arguments.      C:\Documents and Settings\marc.viste\Desktop\howtofolderwatcher\Form1.vb      5      53      howto_net_filesystemwatcher
Error      3      Event 'Load' cannot be found.      C:\Documents and Settings\marc.viste\Desktop\howtofolderwatcher\Form1.vb      14      103      howto_net_filesystemwatcher
Error      4      Name 'lstFiles' is not declared.      C:\Documents and Settings\marc.viste\Desktop\howtofolderwatcher\Form1.vb      76      9      howto_net_filesystemwatcher
Error      5      Option Strict On prohibits operands of type Object for operator '&'.      C:\Documents and Settings\marc.viste\Desktop\howtofolderwatcher\Form1.vb      76      61      howto_net_filesystemwatcher
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26294064
Which solution are you trying to implement?   Give us the ID # to the left of the posters name...   =)
EE-Comment-ID-Number.jpg
0
 

Author Comment

by:cpservice
ID: 26294090
01/11/10 09:00 PM, ID: 26290103
      
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26294265
Duh...that's mine.  ;)

Error #1 - Go to Project --> Properties and change the "Startup Object" entry to the Form.  Is the "Enable Applciation Framework" box checked?  What are you doing in Sub Main?

Error #2 - What kind of Project did you start with?...
Error #3 - See Error #2

Error #4 - I didn't RE-POST the "#Region " Windows Form Designer generated code" section so you'll have to stick that back into your code!

Error #5 - Turn Option Strict Off <or> Change:

        lstFiles.Items.Add(Now.ToString() & " Processed " & e.UserState)

To:

        lstFiles.Items.Add(Now.ToString() & " Processed " & e.UserState.ToString())

0
 

Author Comment

by:cpservice
ID: 26294365
The startup entry is Form1. Although sub main error happenned  when I copy and pasted your code...

I'll make the adjustments and give it all a shot. Thank you!
0
 

Author Comment

by:cpservice
ID: 26294418
Windows form project from the start.

Still get error :

Error      1      'System.Collections.Queue' has no type parameters and so cannot have type arguments.      C:\Documents and Settings\marc.viste\Desktop\howtofolderwatcher\Form1.vb      86      53      howto_net_filesystemwatcher


And it highlights string in (of string) as being the issue. :
 Public Shared ToBeProcessed As New Queue(Of String)
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26294503
Hmmm....go to Project --> Properties and switch to the References Tab.

Make sure you have "System.Collections" and "System.Collections.Generic" in there.


ReferencesTab.jpg
0
 

Author Comment

by:cpservice
ID: 26294749
Missing the generic one.

Added this line at top:
Imports System.Collections.Generic
0
 

Author Comment

by:cpservice
ID: 26294811
This works the same as before. If I cut and paste from same drive it works fine but if the file needs to transfer into folder it runs the command too early before the transfer has completed....
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26294895
Yes...it will.  BUT does it retry again until it succeeds?  =\
0
 

Author Comment

by:cpservice
ID: 26294954
It does not try again after the file has completed uploading.

0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26296587
Don't know what to tell ya...there are too many variables here for us to guess where the problem really lies.

I highly suggest you start with a NEW project, manually place the controls onto the form (instead) of using the converted VB6 stuff), and then start with some bare bones code examples from somewhere above.
0
 

Author Comment

by:cpservice
ID: 26296779
Thanks. I already started a new and manually added everyting still get same issue. I'll figure it out.
0
 

Author Comment

by:cpservice
ID: 26297697
is there any reason an if catch exception goto repeat and repeat the command wouldn't work?

probably bad programming but seems like an easy solution... I'm working this now but no luck so far to get the syntax right...
0
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 26303052
How about replacing the Queue with a list and modifying the code accordingly?
0

Featured Post

Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

800 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question