Matlab includes a variety of builtin utility functions that enable easy access to FTP. These functions are basically methods of an FTP object using Matlab’s old class system (for example, the mput function is implemented as mput.m in the %matlabroot%\toolbox\matlab\iofun\@ftp\ folder). These are pretty old files that haven’t changed much in years.
I recently needed to upload files from Matlab onto an FTP server, and discovered that calling mput simply hang Matlab to the point that I needed to kill and restart the Matlab process. The problem was not in the FTP server, since it could be accessed normally using FTP clients such as FileZilla and WinSCP. So it had to be something internal to Matlab. My initial workaround was to create an automation script (using WinSCP in my case) for the file upload. But this kludge is both non-robust as well as slow. A fix to the Matlab problem would be much better.
Some online research yielded others who have complained about similar issues over the years, but I saw no concrete answer. I saw many references online to problems that relate to the combination of passive FTP with Windows 7 / firewall / Java 7, that suggested several fixes (example 1, example 2, example 3, example 4). However, none of them solved the problem: calling mput (or dir etc.) continued to freeze Matlab, forcing either a hard process kill or waiting several minutes for the timeout.
Today, Malcolm Lidierth, author of the Waterloo graphics package, told me that he also saw a similar situation on Mac. Fortunately, Malcolm discovered a much better solution to the problem than my external scripts workaround. It seems that simply setting the Java object underlying Matlab’s FTP object to use passive mode fixes the problem (possibly in addition to the other fixes mentioned above).
This can be done in two manners:
The easiest is to add the following highlighted line in mput.m, on or about line 69 (the exact line may change based on your Matlab release):
... % Upload this file. fis = java.io.FileInputStream(fileObject); h.jobject.enterLocalPassiveMode(); % Use passive modestatus = h.jobject.storeFile(name,fis); fis.close; ...
This works but has several limitations:
- it does not solve the problems of other passive FTP commands such as dir, although they can be solved in a similar manner
- it creates a counter-problem when connecting to non-passive FTP servers – users might wish to make this a parameter of the ftp constructor function
- and of course it requires changing Matlab’s installation files which is problematic in many aspects, as well as non-portable if you ever use your program on another machine or Matlab release.
Here’s a much simpler, portable and flexible solution: simply set the underlying Java object’s passive mode after connecting to the server (using the ftp constructor function) but before using mput or dir or any other command that uses passive FTP mode:
f = ftp('myftpserver.com',username,password); cd(f); sf=struct(f); sf.jobject.enterLocalPassiveMode();mput(f,filename); dir(f); close(f);
Note that we need to connect first, then get the underlying Java reference using the struct hack (since direct access to
f.jobject is prevented), then we enter local passive mode, and only then we call mput to upload the file. If we omit the highlighted line in the script above, then mput (and dir etc.) will hang.
This way, we can programmatically control when to use passive mode, and no changes to the Matlab install files is required: our Matlab script should now work on all platforms and Matlab releases.
Note the seemingly unnecessary call to cd(f) – this is done to ensure a valid connection before setting the passive mode. We should ensure to do this before each call to mput/dir etc., since otherwise, if the connection drops for any reason (e.g., timeout or some other disconnection), then the mput/dir command would reconnect without passive mode (causing a hang). By calling cd(f) we ensure that the connection is done and passive mode is re-entered before mput/dir are called.
As an interesting related note, ftp accepts an undocumented set of optional input parameters following its first 3 documented inputs (hostname, username and password). We can pass one or more of the following parameters in P-V (param name, param value) pairs format: System, LenientFutureDates, DefaultDateFormatStr, RecentDateFormatStr, ServerLanguageCode, ServerTimeZoneId, ShortMonthNames. All of these parameters expect string (char) values, except LenientFutureDates that expects a logical value (true/false). All the parameters have a default value of empty. An explanation of these parameters can be found in Apache’s documentation of the
FTPClientConfig class (Matlab’s ftp uses a plain Apache
FTPClient object, where you can also find an explanation of the enterLocalPassiveMode method that was used above).
Italy visit, Aug 26 – Sep 1, 2015
I will be traveling to north Italy between Aug 26 – Sep 1, 2015. If you happen to be in the area at that time, I will be happy to meet you to discuss how I could bring value to your work. Please email me (altmany at gmail) if you are interested.
Due to my travel, this blog will take a short summer vacation, and will return in early September. Stay tuned!