Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multiple calls to sub for ftp dl, how to wait for finish 1

Status
Not open for further replies.

shyler

Programmer
May 3, 2010
11
US
I tried to make this as clear as possible, hope it's not confusing!

I have a vbs file that I want to do the following:

1) Open a previously created text file that has a listing of an ftp directory.
2) Begin Subroutine
3) Scan that text file to find a particular file name.
4) If the name exists, open cmd and use sendkeys to input the command to open my ftp program and download the file from the aforementioned ftp directory.
5) Determine if the file exists in the local directory and add the file name and whether it was downloaded (or a specific msg if not found in the remote directory) to a new line in a different text file.
6) Exit Subroutine
7) Repeat steps 2-6 for several files (about 15 files in all).
8) Read the second text file and display the information recorded in a msgbox.

Below is my code. So far everything is working great if I run it for only one file. I cannot think of a way to wait until the subroutine finishes for each file before it is called for the next. I've done quite a bit of online searching and have yet to come up with a solution.

I have to go the cmd -> ftp program route for security reasons, although I realize this is likely what's causing the hurdle. Of course, any suggestions on an alternative way to connect to ftp without passing login/password information would be considered. I haven't found anything yet that I think would work, but I am a self-taught jack-of-all-trades kind of programmer so there could very well be some way of which I'm unaware.

Thanks in advance!

Code:
Dim wShell, fso, f, fc, fn, i, finis
Dim oRegEx, objf, strSS, cmatch, smatch
Dim cpath, mpath, opath, spath
Dim mo, da, yr, yrmoda
Dim txtstr, fl, multi, mArray(), j

Set fso = CreateObject("Scripting.FileSystemObject")
Set txtstr = fso.CreateTextFile("C:\MC\tempdirfile\temp.txt", True)
txtstr.Close
Set fso = nothing

cpath = "C:\Program Files\coreftp\coreftp.exe"
mpath = "/ftp_path/"

da = Day(Date)
mo = Month(Date)
yr = Year(Date)

If mo < 10 Then
    mo = "0" & mo
Else
    mo = mo
End If
If da < 10 Then
    da = "0" & da
Else
    da = da
End If
yrmoda = yr & mo & da

Call downloadfiles("blahblahsomefile" & yrmoda, "blahblahsomefilepath", "blah File(s) not found in remote directory.")
Call downloadfiles("blahblahsomeotherfile" & yrmoda, "blahblahsomeotherfilepath", "blahblah File(s) not found in remote directory.")
Call downloadfiles("blahblahyetanotherfile" & yrmoda, "blahblahyetanotherfilepath", "blahblahblah File(s) not found in remote directory.")

spath = "C:\MC\tempdirfile\temp.txt"
MsgBox ReadTextFile(spath)

'''''Function to read 2nd text file and get output for above msgbox
Public Function ReadTextFile(strPath)
    Dim fso, ts, strOutput
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.OpenTextFile(strPath)
    Do Until ts.AtEndOfStream
        strOutput = strOutput & ts.ReadLine & Chr(13)
    Loop            
    ts.Close
    ReadTextFile = strOutput
End Function


'''''Main subroutine
Public Sub downloadfiles(patho, pathf, outp)
    Set oRegEx = CreateObject("VBScript.RegExp")
    oRegEx.Pattern = patho
    oRegEx.IgnoreCase = true

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set objf = fso.OpenTextFile("C:\MC\tempdirfile\tempdirfile.txt", 1)
    i = 0
    multi = ""

    Do Until objf.AtEndOfStream
        strSS = objf.ReadLine
        cmatch = oRegEx.Test(strSS)
        If cmatch Then
            i = i + 1
            If multi = "" Then
                multi = Right(strSS, Len(strSS) - (InStr(strSS, patho) - 1))
            Else
                multi = multi & "|" & Right(strSS, Len(strSS) - (InStr(strSS, patho) - 1))
            End If
        End If
    Loop
    
    Set fso = nothing

    If i > 0 Then
        Set wShell = CreateObject("WScript.Shell")
        wShell.Run("cmd")
        wShell.AppActivate("cmd")
        WScript.Sleep 2000
        
        If InStr(multi,"|") > 0 Then
            mArray = Split(multi,"|")

            For j = 0 to UBound(mArray)
                If InStr(mArray(j),".txt") > 0 Then
                    opath = mpath & mArray(j)
                    wShell.SendKeys(Chr(34) & cpath & Chr(34) & " -s -O -site PCNS -d " & opath & " -p " & pathf & " {ENTER}")
                    msgbox(cpath & chr(34) & opath & chr(34) & pathf)

                    Set fso = CreateObject("Scripting.FileSystemObject")
                    fn = pathf & mArray(j)

                    If fso.FileExists(fn) Then
                        Set fso = CreateObject("Scripting.FileSystemObject")
                        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
                        fl.WriteLine(mArray(j) & " was downloaded.")
                        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
                        WriteLineToFile = fl.ReadAll
                        Set fso = nothing
                    Else
                        Set fso = CreateObject("Scripting.FileSystemObject")
                        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
                        fl.WriteLine(mArray(j) & " was not downloaded.")
                        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
                        WriteLineToFile = fl.ReadAll
                        Set fso = nothing
                    End If
                    
                    Set fso = nothing
                    Set wShell = nothing
                End If
            Next
        Else
            opath = mpath & multi
            wShell.SendKeys(Chr(34) & cpath & Chr(34) & " -s -O -site PCNS -d " & opath & " -p " & pathf & " {ENTER}")

           Set fso = CreateObject("Scripting.FileSystemObject")
           fn = pathf & multi

           If fso.FileExists(fn) Then
               Set fso = CreateObject("Scripting.FileSystemObject")
               Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
               fl.WriteLine(multi & " was downloaded.")
               Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
               WriteLineToFile = fl.ReadAll
               Set fso = nothing
           Else
               Set fso = CreateObject("Scripting.FileSystemObject")
               Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
               fl.WriteLine(multi & " was not downloaded.")
               Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
               WriteLineToFile = fl.ReadAll
               Set fso = nothing
           End If
                
           Set fso = nothing
            Set wShell = nothing
        End If
    Else
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
        fl.WriteLine(outp)
        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
        WriteLineToFile = fl.ReadAll
        Set fso = nothing
    End If
End Sub
 
BTW, this line

msgbox(cpath & chr(34) & opath & chr(34) & pathf)

was just to test the variables were correct. It is not actually part of the sub.
 
I'm going to try again tomorrow with wscript.sleep and see if I can get wait times that will make it work properly. As well as adding the missing EXIT statement so my desktop doesn't become cluttered with cmd's. :p
 
I had a chance to test it today. Worked a treat. Now I just need to figure out how to delete files or transfer them to a different folder on the ftp server. Ideas are always appreciated.

For anyone interested, here's the working code:

Code:
Dim wShell, fso, f, fc, fn, i, finis
Dim oRegEx, objf, strSS, cmatch, smatch
Dim cpath, mpath, opath, spath
Dim txtstr, fl, multi, mArray, j

Set fso = CreateObject("Scripting.FileSystemObject")
Set txtstr = fso.CreateTextFile("C:\MC\tempdirfile\temp.txt", True)
txtstr.Close
Set fso = nothing

cpath = "C:\Program Files\coreftp\coreftp.exe"
mpath = "/ftp_path/"

Call downloadfiles("blahblahsomefile" & yrmoda, "blahblahsomefilepath", "blah File(s) not found in remote directory.")
Call downloadfiles("blahblahsomeotherfile" & yrmoda, "blahblahsomeotherfilepath", "blahblah File(s) not found in remote directory.")
Call downloadfiles("blahblahyetanotherfile" & yrmoda, "blahblahyetanotherfilepath", "blahblahblah File(s) not found in remote directory.")

spath = "C:\MC\tempdirfile\temp.txt"
MsgBox ReadTextFile(spath)

Public Function ReadTextFile(strPath)
    Dim fso, ts, strOutput
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.OpenTextFile(strPath)
    Do Until ts.AtEndOfStream
        strOutput = strOutput & ts.ReadLine & Chr(13)
    Loop            
    ts.Close
    ReadTextFile = strOutput
End Function

Public Sub downloadfiles(patho, pathf, outp)
    Set oRegEx = CreateObject("VBScript.RegExp")
    oRegEx.Pattern = patho
    oRegEx.IgnoreCase = true

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set objf = fso.OpenTextFile("C:\MC\tempdirfile\tempdirfile.txt", 1)
    i = 0
    multi = ""

    Do Until objf.AtEndOfStream
        strSS = objf.ReadLine
        cmatch = oRegEx.Test(strSS)
        If cmatch Then
            i = i + 1
            If multi = "" Then
                multi = Right(strSS, Len(strSS) - (InStr(strSS, patho) - 1))
            Else
                multi = multi & "|" & Right(strSS, Len(strSS) - (InStr(strSS, patho) - 1))
            End If
        End If
    Loop
    
    Set fso = nothing

    If i > 0 Then
        If InStr(multi,"|") > 0 Then
            mArray = Split(multi,"|")

            For j = 0 to UBound(mArray)
                Set wShell = CreateObject("WScript.Shell")
                wShell.Run("cmd")
                wShell.AppActivate("cmd")
                WScript.Sleep 2000
                opath = mpath & mArray(j)
                wShell.SendKeys Chr(34) & cpath & Chr(34) & " -s -O -site PCNS -d " & opath & " -p " & pathf & " {ENTER}"
                WScript.Sleep 5000
                wShell.SendKeys("EXIT {ENTER}")
                WScript.Sleep 5000
                
                Set fso = CreateObject("Scripting.FileSystemObject")
                fn = pathf & mArray(j)

                If fso.FileExists(fn) Then
                    Set fso = CreateObject("Scripting.FileSystemObject")
                    Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
                    fl.WriteLine(mArray(j) & " was downloaded.")
                    Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
                    WriteLineToFile = fl.ReadAll
                    Set fso = nothing
                Else
                    Set fso = CreateObject("Scripting.FileSystemObject")
                    Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
                    fl.WriteLine(mArray(j) & " was not downloaded.")
                    Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
                    WriteLineToFile = fl.ReadAll
                    Set fso = nothing
                End If
                
                Set fso = nothing
                Set wShell = nothing
            Next
        Else
            Set wShell = CreateObject("WScript.Shell")
            wShell.Run("cmd")
            wShell.AppActivate("cmd")
            WScript.Sleep 2000
            opath = mpath & multi
            wShell.SendKeys Chr(34) & cpath & Chr(34) & " -s -O -site PCNS -d " & opath & " -p " & pathf & " {ENTER}", True
            WScript.Sleep 5000
            wShell.SendKeys("EXIT {ENTER}")
            WScript.Sleep 5000

            Set fso = CreateObject("Scripting.FileSystemObject")
            fn = pathf & multi

            If fso.FileExists(fn) Then
                Set fso = CreateObject("Scripting.FileSystemObject")
                Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
                fl.WriteLine(multi & " was downloaded.")
                Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
                WriteLineToFile = fl.ReadAll
                Set fso = nothing
            Else
                Set fso = CreateObject("Scripting.FileSystemObject")
                Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
                fl.WriteLine(multi & " was not downloaded.")
                Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
                WriteLineToFile = fl.ReadAll
                Set fso = nothing
            End If
                
            Set fso = nothing
            Set wShell = nothing
        End If
    Else
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 8, True)
        fl.WriteLine(outp)
        Set fl = fso.OpenTextFile("C:\MC\tempdirfile\temp.txt", 1)
        WriteLineToFile = fl.ReadAll
        Set fso = nothing
    End If
End Sub
 
[1] I would suggest definitively the whole part of using sendkeys be replaced by using wscript.shell's run method using bWaitOnReturn true making the process synchoneous.

[2] It is not infrequent that the sub/function freely uses global variables (mpath, cpath etc...). In that case, you can free up (much) overhead of instantiating fso. Just use one instance of global fso and use everywhere. Even if you use local copy of fso, instantiate once is sufficient. (It makes logic clearer and instantiating it is an expensive operation. But, efficiency may not be the top priority. Getting rid of redundant instantiations makes you look better as a scripter and it reflects doubtful understanding of the logic behind.)

[3] If there would be multiple calls to the downloadfiles function, it is better to establish the array of files to check once and for all rather than each time repeating the same process of reading tempdirfile.txt.

[4] The setting up of "multi" string is unnecessary. If the filename is found good to download, call rightaway the wshshell.run method to get it download. That should be a clearer approach.

[5] The way regex is used is seriously flawed. I would say simpler string/substring comparison would be even more robust in your case.
 
Thank you for your input!

[1] I didn't realize before that you could send cmd commands using run. I will test this as soon as new files are available for download.

[2] Good point. Doh.

[3] I am looking at the possibility of a multidimensional array to check all files in "tempdirfile.txt" at once, and keep each file name tied to the result of the check as well as the other sub parameters. I am not sure yet if I will want to go this route. I did, however, decide to separate the current process into two subs: one to check for files and one to download if the file was found.

[4] Some files that are downloaded are named similarly. For instance, when I call to download file "blahblahblah." I might have a file named "blahblahblah.thisone.txt" and one named "blahblahblah.thatone.txt" to download. This is why I set up the "multi", "mArray" for each.

[5] You're right. I prefer short and simple, but my mind doesn't always work like that right away. Why I must make things more difficult for myself I will never know.

Below is the code as it currently stands. Further suggestions are, of course, always appreciated.

Code:
Dim wShell, fso, txtstr, cpath, mpath, mpath2
Dim objf, strSS
Dim csite, spath, fpath, opath
Dim multi, i, mArray, j
Dim fn, fl

Set fso = CreateObject("Scripting.FileSystemObject")
Set txtstr = fso.CreateTextFile("C:\MC\tempdirfile\temp.txt", True)
txtstr.Close

cpath = "C:\Program Files\coreftp\coreftp.exe"
mpath = "/ftp_path/"
csite = " -s -O -site PCNS -d "
spath = "C:\MC\tempdirfile\temp.txt"
fpath = "C:\MC\tempdirfile\tempdirfile.txt"

Call checkfiles("blahblahsomefile", "blahblahsomefilepath", "thisparticular File(s) not found in remote directory.")
Call checkfiles("blahblahsomeotherfile", "blahblahsomeotherfilepath", "thatother File(s) not found in remote directory.")
Call checkfiles("blahblahyetanotherfile", "blahblahyetanotherfilepath", "thisorthat File(s) not found in remote directory.")

MsgBox ReadTextFile(spath)

Public Function ReadTextFile(strPath)
    Dim ts, strOutput
    Set ts = fso.OpenTextFile(strPath)
    Do Until ts.AtEndOfStream
        strOutput = strOutput & ts.ReadLine & Chr(13)
    Loop
    ts.Close
    ReadTextFile = strOutput
End Function

Public Sub checkfiles(patho, pathf, outp)
    Set objf = fso.OpenTextFile(fpath, 1)
    i = 0
    multi = ""

    Do Until objf.AtEndOfStream
        strSS = objf.ReadLine
        If InStr(strSS, patho) > 0 Then
            i = i + 1
            If multi = "" Then
                multi = Right(strSS, Len(strSS) - (InStr(strSS, patho) - 1))
            Else
                multi = multi & "|" & Right(strSS, Len(strSS) - (InStr(strSS, patho) - 1))
            End If
        End If
    Loop
    
    If i > 0 Then
        Call downloadfiles(multi, patho, pathf, outp)
    Else
        Set fl = fso.OpenTextFile(spath, 8, True)
        fl.WriteLine(outp)
        Set fl = fso.OpenTextFile(spath, 1)
        WriteLineToFile = fl.ReadAll
        fl.Close
    End If
End Sub

Public Sub downloadfiles(multi, patho, pathf, outp)
    If InStr(multi,"|") > 0 Then
        mArray = Split(multi,"|")

        For j = 0 to UBound(mArray)
            opath = mpath & mArray(j)
            fn = pathf & mArray(j)
            
            Set wShell = CreateObject("WScript.Shell")
            wShell.Run("cmd /c " Chr(34) & cpath & Chr(34) & csite & opath & " -p " & pathf, 7, true)
            Set wShell = nothing

            If fso.FileExists(fn) Then
                Set fl = fso.OpenTextFile(spath, 8, True)
                fl.WriteLine(mArray(j) & " was downloaded.")
                Set fl = fso.OpenTextFile(spath, 1)
                WriteLineToFile = fl.ReadAll
                fl.Close
            Else
                Set fl = fso.OpenTextFile(spath, 8, True)
                fl.WriteLine(mArray(j) & " was not downloaded.")
                Set fl = fso.OpenTextFile(spath, 1)
                WriteLineToFile = fl.ReadAll
                fl.Close
            End If
        Next
    Else
        opath = mpath & multi
        fn = pathf & multi
        
        Set wShell = CreateObject("WScript.Shell")
        wShell.Run("cmd /c " Chr(34) & cpath & Chr(34) & csite & opath & " -p " & pathf, 7, true)
        Set wShell = nothing

        If fso.FileExists(fn) Then
            Set fl = fso.OpenTextFile(spath, 8, True)
            fl.WriteLine(multi & " was downloaded.")
            Set fl = fso.OpenTextFile(spath, 1)
            WriteLineToFile = fl.ReadAll
            fl.Close
        Else
            Set fl = fso.OpenTextFile(spath, 8, True)
            fl.WriteLine(multi & " was not downloaded.")
            Set fl = fso.OpenTextFile(spath, 1)
            WriteLineToFile = fl.ReadAll
            fl.Close
        End If
    End If
End Sub

Set fso = nothing
 
[5.1] If I may add some substance to the reason why I said your use of regex makes the script less robust than simple string/substring comparision. I am quite at home of using regex, so I have no problem of you using it. But, you've to use it more correct, free from any consideration of efficiency.

[5.2] If you construct your pattern more like this, I would say, depite all the criticism of efficiency, it becomes more proper.

>oRegEx.Pattern = patho
[tt]oRegEx.Pattern = replace(patho,".","\.") & "\s*$"[/tt]

It would more robustly match the filename against all oddity. The odd still is on the leading characters is quite arbitrary and out of control. If you want to match exactly, then it would need to be this.

[tt]oRegEx.Pattern = "^\s*" & replace(patho,".","\.") & "\s*$"[/tt]

In that case, it is just matching the trimmed version of the whole string. That's why I said in this situation, a simple string comparison would do better. The above consideration does not even take into account of special characters acceptable to be in the filename and need to escape in a regexp's pattern! These are the reasons of the breakdown of robustness.
 
I am always learning as I go, and am not too familiar with regexp yet, but I think I see your point. In my case, each particular file always begins with exactly the same string. I certainly lose a few lines of code by doing a simple InStr, if nothing else!

On another note. I've tested the script using the run method, and after tinkering with it a bit I got it to work. That cleans things up quite a bit, and now I don't have to worry that the sleep won't be long enough for a big file. Thank you so much for your help! Only thing left to figure out is how to move files from one folder to another on the ftp server and I am done. Hurrah! :)

Code:
cpath = csite & opath & " -p " & pathf & " {ENTER}"
wShell.Run "coreftp.exe" & cpath, 7, true
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top