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!

VBA to get list of files on ftp server 3

Status
Not open for further replies.

DevelopV

Technical User
Mar 16, 2012
113
ZA
In Access 2010 I need to get a list of all files in a specific directory on an ftp server and download them to my hard drive.
I never know how many files, or their file names, there are on the ftp server at time of download.

What is the best way to accomplish this?

Many thanks
 
OK. Thanks
I will give it a go and let you know
 
Very clever and simple!

Just a question:
Code:
Private Sub Command0_Click()
    Dim myFolderItem As FolderItem
    Dim localfolder As Folder
    Dim myShell As New Shell
    Dim MyFiles As String
    
    MyFiles = ""
    For Each myFolderItem In ftpList("[URL unfurl="true"]www.mydomain.com/public_html/tim/webexport/")[/URL] 'Each item could be a folder or a file
        Set localfolder = myShell.Namespace("c:\temp")
        localfolder.CopyHere myFolderItem
   
        MyFiles = MyFiles & myFolderItem.Name & ";"
    Next
    
    Me.List1.RowSource = MyFiles
End Sub
Not all the file names are returned. I have 2 .csv files and 1 .jpeg files in the folder on the internet. Only the 2 .csv files are returned. Why not the .jpg?
 
Of course, if you use my code, you get a progress meter for free...

Really? , looks like I might have to look at ripping your FTP code and refactoring ;-)

Pluging into the wininet.dll is a bit of a pain and a very old way of doing it, wonder how much longer the wininet.dll we be around for?

Regarding your code Mike, how do you trap / get errors through the 'shell' ?

Is this like exectuing a DOS command that runs completely independent from the application so trapping errors isn't possible?

I'm also curious, I thought allowing the FTP protocol via a browser to access FTP sites passing in username and password was deprecated; or was it just poorly supported a few years back and now become a standard?

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
Hi strongm

Code:
Public Function ftpList(strFTPlocation As String, Optional strUser As String, Optional strPassword As String) As FolderItems
    Dim myShell As Shell
    Dim strConnect As String
    
    Set myShell = New Shell
    strConnect = strUser & ":" & strPassword & "@"
    Set ftpList = myShell.Namespace("FTP://" & strConnect & strFTPlocation).Items '("ftp://user:password@ftp.site.com")
   [highlight #EF2929] does strFTPlocation above include the folders for the files? e.g [URL unfurl="true"]www.mydomain.com/public_html/tim/webexport/[/URL]
    this seems like a duplication in code![/highlight]
End Function

Code:
Private Sub Command0_Click()
    Dim myFolderItem As FolderItem
    Dim localfolder As Folder
    Dim myShell As New Shell
    Dim MyFiles As String
    
    MyFiles = ""
    For Each myFolderItem In ftpList("[URL unfurl="true"]www.mydomain.com/public_html/tim/webexport/")[/URL] 'Each item could be a folder or a file
        Set localfolder = myShell.Namespace("c:\temp")
        localfolder.CopyHere myFolderItem
        MyFiles = MyFiles & myFolderItem.Name & ";"
    Next
    
    Me.List1.RowSource = MyFiles
End Sub

I am a little unsure with the syntax!
My ftp domain is: ftp.mydomain.com
The folder I want to interrogate is: /public_html/tim/webexport/

What is the correct syntax for:
Set ftpList = myShell.Namespace("FTP://" & strConnect & strFTPlocation).Items
For Each myFolderItem In ftpList("
Also how do I copy a file from one ftp folder to another?

Do I use localfolder.CopyHere myFolderItem for copying files in both directions? i.e "local drive to ftp" and "ftp to local drive"

Many thanks for you help
 
>does strFTPlocation above include the folders for the files
Yes.

>this seems like a duplication in code!
How so?

>Do I use localfolder.CopyHere myFolderItem for copying files in both directions? i.e "local drive to ftp" and "ftp to local drive"
Yes. Although in my example localdrive is a normal windows folder, not an FTP location - but there is no reason why it cannot be.
 
>via a browser

Ah, but this isn't via the browser, it is via the shell (i.e. explorer); MS moved the functionality out of the browser some years ago, but didn't necessarily advertise that they had simply moved it into the shell instead. If you open an explorer window, and then type ftp://<an_ftp_site> you'll be pleasantly surprised. Indeed, once Explorer has figured out you are connecting to an FTP site it'll kindly add a new "Login As" menu item to the Explorer menus in case the site needs credentials.

>how do you trap / get errors through the 'shell' ?

That's the main drawback of the technique. Almost all of the error handling is handled by the shell, and you never get to see it
 
Aha, saw the FTP protocol and assumed it was via iExplorer not Explorer!

I guess as you say , there are pro's and con's for both methods... in my case... if it aint broke :)

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
I guess as you say , there are pro's and con's for both methods... in my case... if it aint broke

I agree!

1DMF, can you please post the code to get a file from an FTP server with the progress meter?

Many thanks
 
1DMF, can you please post the code to get a file from an FTP server with the progress meter
Already done at 11 Feb 13 15:12
 
missed that! Sorry

I can't get it to work!


FTPFile pubInternetDomainName, pubInternetFTPUserName, pubInternetFTPPassword, FolderToCopyTo, FileToCopy, FileToCopyFrom, "ASCII"

where
FileToCopy = webexportcustomers.csv
FileToCopyFrom = public_html/tim/webexport
FolderToCopyTo = C:\Temp\WebImport\webexportcustomers.csv

All I get is a "Upload Failed" error on line
' Write remainder to FTP checking for success
=====>>> If InternetWriteFile(hFile, FileData(0), iSize Mod BUFFER_SIZE, iWritten) = 0 Then
MsgBox "Upload - Failed!"
ShowError

ShowError = "Last Server Response : "
sErr = null

Have I got the syntax wrong?
 
>I agree!
>I can't get it to work!

Well, clearly it is broken for you ... ;-)


 
You asked for code to GET a file 'from' FTP then posted code relating to uploading a file 'to' FTP?

to GET a file FROM FTP ...

here is the function...
Code:
Function FTPGet(ByVal HostName As String, _
    ByVal Username As String, _
    ByVal Password As String, _
    ByVal LocalFileName As String, _
    ByVal RemoteFileName As String, _
    ByVal sDir As String, _
    ByVal sMode As String, Optional ByRef iCnt = 1, Optional ByRef iTot = 1) As Boolean
    
On Error GoTo Err_Function

' Declare variables
Dim hConnection, hOpen, hFile  As Long ' Used For Handles
Dim iSize As Long ' Size of file for download
Dim iMaxSize As Long
Dim Retval As Variant ' Used for progress meter
Dim iRead As Long ' Used by InternetReadFile to report bytes downloaded
Dim iLoop As Long ' Loop for downloading chunks
Dim iFile As Integer ' Used for Local file handle
Dim FileData(BUFFER_SIZE - 1) As Byte ' buffer array of BUFFER_SIZE (100) elements 0 to 99

' Open Internet Connecion
hOpen = InternetOpen("FTP", 1, "", vbNullString, 0)

' Connect to FTP
hConnection = InternetConnect(hOpen, HostName, INTERNET_DEFAULT_FTP_PORT, Username, Password, INTERNET_SERVICE_FTP, IIf(PassiveConnection, INTERNET_FLAG_PASSIVE, 0), 0)

' Change Directory
Call FtpSetCurrentDirectory(hConnection, sDir)

' Open Remote File
hFile = FtpOpenFile(hConnection, RemoteFileName, GENERIC_READ, IIf(sMode = "Binary", FTP_TRANSFER_TYPE_BINARY, FTP_TRANSFER_TYPE_ASCII), 0)

' Check for successfull file handle
If hFile = 0 Then
    MsgBox "Internet - Failed!"
    ShowError
    FTPGet = False
    GoTo Exit_Function
End If

' Set Download Flag to True
FTPGet = True

' Set file size
iSize = FtpGetFileSize(hFile, iMaxSize)

' Get next file handle number
iFile = FreeFile

' Open local file
Open LocalFileName For Binary Access Write As iFile

' Iinitialise progress meter
Retval = SysCmd(acSysCmdInitMeter, "Downloading File '" & RemoteFileName & "' - " & iCnt & " of " & iTot, iSize / 1000)

' Loop file size
For iLoop = 1 To iSize \ BUFFER_SIZE
        
    ' Update progress meter
    Retval = SysCmd(acSysCmdUpdateMeter, (BUFFER_SIZE * iLoop) / 1000)

    ' Read chunk from FTP checking for success
    If InternetReadFile(hFile, FileData(0), BUFFER_SIZE, iRead) = 0 Then
        MsgBox "Download - Failed!"
        ShowError
        FTPGet = False
       GoTo Exit_Function
    Else
        ' Check buffer was read
        If iRead <> BUFFER_SIZE Then
            MsgBox "Download - Failed!"
            ShowError
            FTPGet = False
            GoTo Exit_Function
        End If
    End If
    
    'put file data
    Put iFile, , FileData
    
Next iLoop

' Handle remainder using MOD

    ' Update progress meter
    Retval = SysCmd(acSysCmdUpdateMeter, iSize / 1000)
    
    ' Write remainder to file checking for success
    If InternetReadFile(hFile, FileData(0), iSize Mod BUFFER_SIZE, iRead) = 0 Then
        MsgBox "Download - Failed!"
        ShowError
        FTPGet = False
        GoTo Exit_Function
    Else
        ' Check buffer was read
        If iRead <> iSize Mod BUFFER_SIZE Then
            MsgBox "download - Failed!"
            ShowError
            FTPGet = False
            GoTo Exit_Function
        End If
    End If
               
    ' Put file data
    Put iFile, , FileData
    
Exit_Function:

' remove progress meter
Retval = SysCmd(acSysCmdRemoveMeter)

'close local file
Close iFile

'close remote file
Call InternetCloseHandle(hFile)

' Close Internet Connection
Call InternetCloseHandle(hOpen)
Call InternetCloseHandle(hConnection)

Exit Function

Err_Function:
MsgBox "Error in FTPGet : " & err.Description

GoTo Exit_Function

End Function

Then call it with...
Code:
sServer = "127.0.0.1"
sUID = "MyUSerID"
sPWD = "MyPassword"
sRemoteFileName = "MyFile.csv"
sPath = "C:\MyPath\"
sMode = "ASCII"

' download file
If Not FTPGet(sServer, sUID, sPWD, sPath & sRemoteFileName, sRemoteFileName, sRemoteFolder, sMode) Then
    MsgBox "Error downloading file, please seek support!"
End If

There are two optional parameters that can be passed at the end should you be downloading mutliple files in a loop and want the meter to display a (1 of 5) type message.

Code:
Dim i As Integer
Dim bOK As Boolean

For i = 0 To UBound(myFiles)
    bOK = FTPGet(sServer, sUID, sPWD, sPath & myFiles(i), myFiles(i), sRemoteFolder, sMode, i+1, Ubound(myFiles)+1) 
Next

So to recap the parameters

1. FTP Server IP
2. Username
3. Password
4. Path including drive letter and filename including extention that you want the file to save as when downloaded
5. Name of file on FTP server
6. Folder location of file on FTP server
7. Download mode (either "ASCII" or "Binary")
8. Current number count of file being downloaded (default = 1)
9. Total number of files to be downloaded (default = 1)

I really can't explain it any more simpler!

And remember - I've not put any error handling in the loop, so you might want to check bOK on each pass and handle errors ;-)

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
And just for fun here's my short version of FTPGet (fractionally different calling convention), with a little bit of error stuff thrown in just to show it can be done ...

Code:
[blue]Public Sub FTPGet(ByVal strFTPLocation As String, ByVal FullLocalPath As String, ByVal strFileName As String, Optional ByVal strUser As String, Optional ByVal strPassword As String)
    Dim localfolder As Folder
    Dim myShell As New Shell
    Dim strConnect As String
    Dim ftpFile As FolderItem
    
    If strUser <> "" Then strConnect = strUser & ":" & strPassword & "@"
    With myShell.Namespace("FTP://" & strConnect & strFTPLocation)
        Set localfolder = myShell.Namespace(FullLocalPath)
        If .Items.Count <> 0 Then
            If Not .Items.Item(strFileName) Is Nothing Then
                localfolder.CopyHere .Items.Item(strFileName), &H4
            Else
                Err.Raise vbObjectError + 513, "FTPGet", "File " & strFileName & " not found in " & .Title
            End If
        Else
            Err.Raise vbObjectError + 514, "FTPGet", "Bad username/password or bad FTP folder: " & strFTPLocation
        End If
    End With
    
End Sub[/blue]
 
Your instructions are very clear, thank you. Thanks also for your patience

I am using: FTPGet(sServer, sUID, sPWD, sPath & sRemoteFileName, sRemoteFileName, sRemoteFolder, sMode)
and am populating like this:

FTPGet " myUserName, myPassword,"C:\Temp\webexportareas.csv","webexportareas.csv","public_html/tim/webexport","ASCII"

The domain, user name & password work because I use the same to upload files

The code fails on this line:

If InternetReadFile(hFile, FileData(0), iSize Mod BUFFER_SIZE, iRead) = 0 Then

hFile = 13369368
FileData(0) = 0
iSize = -1
BUFFER_SIZE = 100
iRead = 0

Are these values correct? If not, what should they be?

Many thanks
 
Have you got
Code:
Option Explicit
at the top of your modules?

If not change "Option Compare Database" to the above and compile the code, just so we can be sure you declared all the global constants.

Also when you say failed...with what? can we have an error message and number please.

You need to provide more info!

I have that exact code running in production, so I know it works, I need to see some code and error messages before I can attempt to help debug.

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
In fact to make it easy for you, I have created a separate FTP_Functions module with the core functions in it and all the wininet.dll API delcarations and constants.

Simply download [URL unfurl="true"]http://dance-music.org/FTP_Functions.zip[/url] , extract the .bas file then import it into the 'module' section of your access project.

Then you know you have an ecapsulated module with working FTP functions, hopefully we can then narrow down any errors to the code you are trying to use to access these functions.

And I admit the module is messy and could do with refactoring and removing popup messages that don't belong in a model. If it was properly refactored to an object it would be a whole lot better... but hey, it was written in 2006 by a 'noobie' me; who now knows better! but it works, so you can always fix/refactor it yourself ;-)

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
the the top of the module I have:
Option Compare Database
Option Explicit

The error messages I get are:
Download failed
Last Server Response:

I have commented out my code so there are no duplicate calls.
I have imported your FTP_Functions and I get the same error, on the same line!

What I can't understand is that the file upload (FTPFile) works.
Do I need to apply a particular vba reference?
 
I don't think so I have ..

VBA
Access 14.0 Object Library
OLE Automation
MS Internet Controls
MS Office 14.0 ADeO
MS VB Reg Exp

can I see the values you are using to call the function (obfuscating user credentials / IP of course)

It could be you are trying to get it to save to a folder or root of C: drive and don't have the right permissions?

make sure you cretae a folder that has full permissions for everyone and put that as the target location.

Also if this is to a *nix FTP server, check the case of the file name your trying to retrieve as well as remote folder path.

I asssume it is the first "Download failed" msgbox being triggered?

number the messages to be sure that's where it is failing.

That is not a bug error but a message box due to the value of a return when the attempt is made, so double check everything is correct.

If using an array for filename , interogate the variable to be sure it contains the corrrect info.

Also how big is the file? perhaps you need to increase the buffer size as it is currently set to 100?


"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
FTPGet " myUserName, myPassword,"C:\Temp\webexportareas.csv","webexportareas.csv","public_html/tim/webexport","ASCII"

The file size is 400Kb and is a .csv file

This where it fails:
' Write remainder to file checking for success
If InternetReadFile(hFile, FileData(0), iSize Mod BUFFER_SIZE, iRead) = 0 Then
MsgBox "Download - Failed!"
ShowError
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top