Excel / 如何使用VBA連線FTP

VBA可以利用多種方式連結FTP

綜合網路上的參考資料

有2種方式是我嘗試之後可以理解並且可運作的

第1種是引用 windows shell (Shell.Application) 的Folder物件來取得ftp資料夾內容

第2種跟第1種有點類似,不過是先產生ftp 命令的參數文件,再透過Excel內建的shell函數來執行windows內建的ftp程式+command line

前者可以取得ftp內所有資料的內容與路徑

後者是單純操作指令


1.windows shell (Shell.Application) 的Folder物件

除了引用shell之外,為了能夠下載檔案

還需要引用另一個函示庫 URLDownloadToFileA

#If VBA7 Then
    Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _
      Alias "URLDownloadToFileA" ( _
        ByVal pCaller As LongPtr, _
        ByVal szURL As String, _
        ByVal szFileName As String, _
        ByVal dwReserved As Long, _
        ByVal lpfnCB As LongPtr _
      ) As Long
#Else
    Private Declare Function URLDownloadToFile Lib "urlmon" _
      Alias "URLDownloadToFileA" ( _
        ByVal pCaller As Long, _
        ByVal szURL As String, _
        ByVal szFileName As String, _
        ByVal dwReserved As Long, _
        ByVal lpfnCB As Long _
      ) As Long
#End If

 

也可以引用 shdocvw.dll

#If VBA7 Then
    Private Declare PtrSafe Function DoFileDownload Lib "shdocvw.dll" _
        (ByVal lpszFile As String) As Long
#Else
    Private Declare Function DoFileDownload Lib "shdocvw.dll" _
        (ByVal lpszFile As String) As Long

 

這個方式會透過瀏覽器的方式執行下載

主程式

將ftp網址 , 帳號 , 密碼傳到自訂的類別FTPSearch取得ftp資料夾的相關資訊

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Sub Test()
  Dim Files As Collection
  Dim I     As Long
  Dim sPath As String
  sPath = Excel.ThisWorkbook.Path 'excel VBA所在資料夾路徑
  
  Set Files = FTPSearch("ftp網址", "帳號", "密碼") 'ftp網址 , 帳號 , 密碼
  
  For I = 1 To Files.Count
    Debug.Print Files.Item(I) '列出所有檔案路徑
  Next I
  
  '#1
  Debug.Print Files.Count
  URLDownloadToFile 0, "目標檔案下載路徑", sPath & "\檔案名稱.副檔名", 0, 0  '0,目標檔案下載路徑,本機儲存路徑+檔案名稱,0,0

  '#2
  Dim sFileUrl As String
  sFileUrl = StrConv("目標檔案下載路徑", vbUnicode)
  'Debug.Print sFileUrl
  DoFileDownload sFileUrl
  
End Sub

 

自訂的類別FTPSearch

會先判別資料夾是否有上一層等等,再將相對應的參數傳到FTPSearchWithShell

自訂的FTPSearchWithShell

取得資料夾路徑,最後的FTPSearch就是一個紀錄所有檔案的完整路徑的Collection

最終回傳到主程式的Files變數

(Collection 有點類似 python的元組,一維陣列,儲存之後不能修改值)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Public Property Get FTPSearch(ByVal FTPUrl As String, _
        Optional ByVal UserName As String, _
        Optional ByVal PassWord As String, _
        Optional ByVal Port As Integer) As Collection
                           
  Dim objShell  As Object, objFolder As Object
  
  On Error Resume Next
  
  If Len(FTPUrl) Then
    If Len(UserName) Then FTPUrl = UserName & ":" & PassWord & "@" & FTPUrl
    If Port > 0 Then FTPUrl = FTPUrl & ":" & Port
    Set objShell = CreateObject("Shell.Application")
    Set objFolder = objShell.Namespace("FTP://" & FTPUrl)
  End If
  Set FTPSearch = New Collection
  If objFolder Is Nothing Then Exit Function
  
  With objFolder
    If .ParentFolder.Self.IsFolder Then                           '判斷是否還有上一層
      If .ParentFolder.ParseName(.Self.Name) Is Nothing Then
        Debug.Print "Error:Invalid Path!"
      ElseIf objFolder.Self.IsBrowsable Then
        Debug.Print "Error:Invalid Parameter!"
      ElseIf objFolder.Self.IsFolder Then
        Debug.Print "Start search files in path..."
        With objFolder
          FTPSearchWithShell FTPSearch, .ParentFolder.ParseName(.Self.Name).GetFolder
        End With
        Debug.Print "Files search completed."
      End If
    ElseIf objFolder.Self.IsFolder Then
      Debug.Print "Start search files in path..."
      With objFolder
        FTPSearchWithShell FTPSearch, objFolder '將 FTPSearch-要建立的屬性 與 objFolder-ftp根目錄  傳到 FTPSearchWithShell 記錄檔案路徑
      End With
      Debug.Print "Files search completed."
    End If
  End With
End Property
'
'記錄檔案路徑
'
Private Sub FTPSearchWithShell(ByVal Searched As Collection, ByVal Folder As Object, Optional ByVal strPath As String)
  Dim FolderItem  As Object
  Dim objFolder   As Object
  Dim subSearch   As New Collection '類似 python的元組
  
  On Error Resume Next
  
  If Len(strPath) = 0 Then
    Set objFolder = Folder
    Do While (objFolder.ParentFolder.Self.IsFolder)
      strPath = objFolder.Self.Name & "/" & strPath
      Set objFolder = objFolder.ParentFolder
    Loop
    strPath = objFolder.Self.Path & strPath
  End If
  
  If Folder.Items.Count > 0 Then
    Set subSearch = New Collection
    For Each FolderItem In Folder.Items
      With FolderItem
        If .IsFolder Then
          Set Folder = .GetFolder
          If Folder.Items.Count Then subSearch.Add Folder
        ElseIf .IsBrowsable Then
          Searched.Add strPath & .Name
        End If
      End With
    Next FolderItem
   
    For Each Folder In subSearch
      FTPSearchWithShell Searched, Folder
      DoEvents
    Next Folder
  End If
End Sub

 

2.透過Excel內建的shell函數來執行ftp 命令的參數文件

比較需要留意的是#14 非文字檔案都要用二進制模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Sub FTP_SHELL()
    Dim strPNAME As String                        '參數文件名
    Dim nFNO As Integer                           '文件編號
    
    strPNAME = ThisWorkbook.Path & "\ftptest.txt" '文件名生成
    nFNO = FreeFile                               '選取空的文件編號
    
    Open strPNAME For Output As #nFNO             '生成新的文件
    
    Print #nFNO, "open ftp網址"                    'open主机名
    Print #nFNO, "user 帳號 密碼"                  'user命令 用戶名 密碼
    Print #nFNO, "cd WWW"                         '切換至WWW資料夾
    Print #nFNO, "pwd"                            '顯示目前工作目錄
    Print #nFNO, "binary"                         '轉換成二進制模式
    Print #nFNO, "get 1101224.jpg " & ThisWorkbook.Path & "\1101224.jpg"
    Print #nFNO, "bye"                            '關閉 ftp
    
    Close #nFNO                                   '關閉參數文件
                                                  
    Shell "ftp -n -s:" & strPNAME                 'shell啟動 ftp 執行command line
    
    'Application.Wait (Now + TimeValue("0:00:05")) '程式暫停  避免還沒下載檔案
    
    'Dim xFile As String
    'xFile = Dir(strPNAME)
    
    'Debug.Print xFile
    
'    If xFile <> "" Then
'        Kill strPNAME
'    End If
End Sub

 

#24-31

利用一個判斷式來刪除ftp參數文件

因為裡面有ftp的帳密

而因為程式執行速度很快

所以在下載檔案之後,暫停程式5秒

才執行刪除的程序

 

參考資料

[發問] vba 讀取 ftp 裡面的檔案清單

[原创] 使用EXCEL VBA操作FTP服务器的技术汇总(附源代码)

如何用VBA实现网上下载文件?

可編寫腳本的殼層物件

Shell 函數

VB6之迴光返照- 常用下載檔案的方式

[CMD101 心得/筆記] 指令篇

在 Windows 的 DOS命令提示號下使用 FTP

ftp.exe