FTP as easy as 1-2-3
Documentation | Download
Version 2: (2011-06-26)
- All the functions wrapped into a class
ie, NO global variables, except the Class (FTP) itself
- Multiple FTP connections possible with same class
- Asynchronous mode is now fully functional! (Read notes below also)
- No need to call .Close(), clean-up is done when ftp object is deleted.
Using as a class: You'll have to include this file in your script.
#Include FTP.ahk oFTP := new FTP()Using as a library: If this library is in any of your lib folders, no need to #Include, you can initialize the FTP object like so
oFTP := FTPv2()
History:
Original FTP Functions by Olfen & Andreone - thread 10393, modified by ahklerner - post
Modified by me for AHK_L - thread 67370 (many modifications/functions added, see thread for details)
Example:
;; FTP Class Example - http://www.autohotkey.com/forum/viewtopic.php?t=73544 ;; Synchronous mode example ;;== USER SETTINGS =============== Server := "ftp.autohotkey.net" UserName := "my_username" Password := "my_password" UploadFile := "D:\Temp\Test.zip" ;;== END USER SETTINGS =========== #Include FTP.ahk ftp1 := new FTP() ftp1 ? TTip("InternetOpen Success") : Quit("Could not load module/InternetOpen") ; connect to FTP server ftp1.Open(Server, UserName, Password) ? TTip("Connected to FTP") : Quit(ftp1.LastError) ; get current directory sOrgPath := ftp1.GetCurrentDirectory() sOrgPath ? TTip("GetCurrentDirectory : " sOrgPath) : Msg(ftp1.LastError) ; create a new directory 'testing' ftp1.CreateDirectory("testing") ? TTip("Created Directory ""testing""") : Msg(ftp1.LastError) ; set the current directory to 'root/testing' ftp1.SetCurrentDirectory("testing") ? TTip("SetCurrentDirectory ""testing""") : Msg(ftp1.LastError) ; upload this script file ftp1.PutFile(A_ScriptFullPath, A_ScriptName) ? TTip("PutFile success!") : Msg(ftp1.LastError) ; rename script to 'mytestscript.ahk' ftp1.RenameFile(A_ScriptName, "MyTestScript.ahk") ? TTip("RenameFile success!") : Msg(ftp1.LastError) ; enumerate the file list from the current directory ('root/testing') TTip("Enumerating files in directory ""/testing/""") item := ftp1.FindFirstFile("/testing/*") MsgBox % "Name : " . item.Name . "`nCreationTime : " . item.CreationTime . "`nLastAccessTime : " . item.LastAccessTime . "`nLastWriteTime : " . item.LastWriteTime . "`nSize : " . item.Size . "`nAttribs : " . item.Attribs Loop { if !(item := ftp1.FindNextFile()) break MsgBox % "Name : " . item.Name . "`nCreationTime : " . item.CreationTime . "`nLastAccessTime : " . item.LastAccessTime . "`nLastWriteTime : " . item.LastWriteTime . "`nSize : " . item.Size . "`nAttribs : " . item.Attribs } ; retrieve the file from the FTP server ftp1.GetFile("MyTestScript.ahk", A_ScriptDir . "\MyTestScript.ahk", 0) ? TTip("GetFile success!") : Msg(ftp1.LastError) ; delete the file from the FTP server ftp1.DeleteFile("MyTestScript.ahk") ? TTip("DeleteFile success!") : Msg(ftp1.LastError) ; upload a file with progress ftp1.InternetWriteFile( UploadFile ) ? TTip("InternetWriteFile success!") : Msg(ftp1.LastError) ; download a file with progress SplitPath,UploadFile,fName,,fExt ftp1.InternetReadFile( fName , "delete_me." fExt) ? TTip("InternetReadFile success!") : Msg(ftp1.LastError) ; delete the file ftp1.DeleteFile( fName ) ? TTip("DeleteFile success!") : Msg(ftp1.LastError) ; set the current directory back to the root ftp1.SetCurrentDirectory(sOrgPath) ? TTip("SetCurrentDirectory to original path: success!") : Msg(ftp1.LastError) ; remove the direcrtory 'testing' ftp1.RemoveDirectory("testing") ? TTip("RemoveDirectory ""\testing"" success!") : Msg(ftp1.LastError) ; close the FTP connection, free library ftp1 := "" ;__Delete called MsgBox, 64, Success, Tests successfully completed!, 3 ExitApp Quit(Message="") { if Message MsgBox, 16, Error!, %Message%, 5 ExitApp } Msg(Message="") { MsgBox, 64, , %Message%, 5 } TTip(Message="") { ToolTip %Message% }
Uploading - Use PutFile for small files only (otherwise program will be unresponsive till the DllCall is complete). For large files, use InternetWriteFile. If you do not specify a function to handle progress (optional third parameter), upload shows a borderless progress window.
Downloading - Use GetFile for small files only (otherwise program will be unresponsive till the DllCall is complete). For large files, use InternetReadFile. If you do not specify a function to handle progress (optional third parameter), upload shows a borderless progress window.
.CloseSocket() - Call to close only current FTP session. Open a new session with .Open
Asynchronous mode example:
;; FTP Class Example - http://www.autohotkey.com/forum/viewtopic.php?t=73544 ;; Asynchronous Mode example ;; PLEASE NOTE: ;; 1. All output is logged to the stdout, can be only seen if debugger attached ;; or you run it with Scite4Autohotkey ;; 2. The script can do any other work while waiting for AsyncRequestComplete notification ;;== USER SETTINGS =============== Server := "ftp.autohotkey.net" UserName := "my_username" Password := "my_password" UploadFile := "D:\Temp\Test.zip" ;;== END USER SETTINGS =========== ; initialize and get reference to FTP object ftp1 := new FTP(1) ; 1 = Async mode, use default callback function ftp1 ? TTip("InternetOpen Success") : Quit("Could not load module/InternetOpen") OnExit, Cleanup ; connect to FTP server ftp1.Open(Server, UserName, Password) ? TTip("Connected to FTP") : Quit(ftp1.LastError) ; create a new directory 'testing' ftp1.CreateDirectory("testing") SleepWhile() ? TTip("Created Directory ""testing""") : Msg("Create Directory Failed") ; set the current directory to 'root/testing' ftp1.SetCurrentDirectory("testing") SleepWhile() ? TTip("SetCurrentDirectory ""testing""") : Msg("SetCurrentDirectory failed!") ; upload this script file SplitPath,UploadFile,RemoteFile,,fExt ftp1.PutFile(UploadFile, RemoteFile) SleepWhile() ? TTip("PutFile success!") : Msg("PutFile failed!") ; rename script to 'testscript.ahk' ftp1.RenameFile(RemoteFile, (NewLocalFile := "Delete_Me." . fExt)) SleepWhile() ? TTip("RenameFile success!") : Msg("RenameFile failed!") IfExist, % NewLocalFile FileDelete, % NewLocalFile ; retrieve the file from the FTP server ftp1.GetFile(NewLocalFile,A_ScriptDir . "" . NewLocalFile, 0) SleepWhile() ? TTip("GetFile success!") : Msg("GetFile failed!") ; delete the file from the FTP server ftp1.DeleteFile(NewLocalFile) SleepWhile() ? TTip("DeleteFile success!") : Msg("DeleteFile failed!") ; set the current directory back to the root ftp1.SetCurrentDirectory("/") SleepWhile() ? TTip("SetCurrentDirectory to original path: success!") : Msg("SetCurrentDirectory failed") ; remove the directory 'testing' ftp1.RemoveDirectory("testing") SleepWhile() ? TTip("RemoveDirectory ""\testing"" success!") : Msg("RemoveDirectory failed") ExitApp Cleanup: ; close the FTP connection, free library ftp1 := "" ; __Delete Called sleep 1000 ;The request complete will not be triggered, as the last message recieved is 70 = INTERNET_STATUS_HANDLE_CLOSING MsgBox done! exitapp SleepWhile() { global FTP While !FTP.AsyncRequestComplete sleep 50 return (FTP.AsyncRequestComplete = 1) ? 1 : 0 ; -1 means request complete but failed, only 1 is success } Quit(Message="") { if Message MsgBox, 16, Error!, %Message%, 5 ExitApp } Msg(Message="") { MsgBox, 64, , %Message%, 5 } TTip(Message="") { ToolTip %Message% } #Include FTP.ahk
1. You can only make one asynchronous mode connection at a time at present.
2. Functions which use data buffers will not work in asynchronous mode.
(Not because it is not possible in AHK, but because it is not desirable* and beyond my skill level)
These functions include:
- .GetCurrentDirectory()
- .FindFirstFile / .FindNextFile
- .InternetReadFile / .InternetWriteFile
Ref: INFO: Using WinInet APIs Asynchronously Within Visual Basic
To quote the last line of the said article: "This makes using WinInet APIs in Visual Basic asynchronously an undesirable option."
3. Default Async callback function logs all output to stdout
The default async callback function logs all output to stdout, so it can be only seen if debugger attached or you run it with Scite4Autohotkey.
4. The script can continue doing other tasks while waiting for async request complete notification.
5. Callback function:
Note that you can specify the function to call (AsyncMode parameter can be the name of the function). Because callbacks are made during processing of the request, the application should spend little time in the callback function to avoid degrading data throughput on the network. For example, displaying a msgbox in a callback function can be such a lengthy operation that the server terminates the request.
6. Memory/File operations:
In your script, please do not write to the memory/file that has set up to use in the callback function. Both the script and wininet callback may try to write to the same memory location/file and corrupt the file/memory or crash the script.
7. AHK and multithreading:
As AHK uses psuedo-multithreading (it is a single thread only), wininet callbacks will pause the currently executing thread. If the current executing thread is critical, the async notifications may be missed.
MSDN Reference: FTP Sessions (Windows)
Note: FTP Class means that it is for Autohotkey_L/Autohotkey v2 only!