FTPClient encapsulates all the functionality necessary to store and
retrieve files from an FTP server. This class takes care of all
low level details of interacting with an FTP server and provides
a convenient higher level interface. As with all classes derived
from
org.apache.commons.net.SocketClient,
you must first connect to the server with
org.apache.commons.net.SocketClient#connectbefore doing anything, and finally
org.apache.commons.net.SocketClient#disconnectafter you're completely finished interacting with the server.
Then you need to check the FTP reply code to see if the connection
was successful. For example:
boolean error = false;
try {
int reply;
ftp.connect("ftp.foobar.com");
System.out.println("Connected to " + server + ".");
System.out.print(ftp.getReplyString());
// After connection attempt, you should check the reply code to verify
// success.
reply = ftp.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
System.err.println("FTP server refused connection.");
System.exit(1);
}
... // transfer files
ftp.logout();
} catch(IOException e) {
error = true;
e.printStackTrace();
} finally {
if(ftp.isConnected()) {
try {
ftp.disconnect();
} catch(IOException ioe) {
// do nothing
}
}
System.exit(error ? 1 : 0);
}
Immediately after connecting is the only real time you need to check the
reply code (because connect is of type void). The convention for all the
FTP command methods in FTPClient is such that they either return a
boolean value or some other value.
The boolean methods return true on a successful completion reply from
the FTP server and false on a reply resulting in an error condition or
failure. The methods returning a value other than boolean return a value
containing the higher level data produced by the FTP command, or null if a
reply resulted in an error condition or failure. If you want to access
the exact FTP reply code causing a success or failure, you must call
org.apache.commons.net.ftp.FTP#getReplyCode after
a success or failure.
The default settings for FTPClient are for it to use
FTP.ASCII_FILE_TYPE
,
FTP.NON_PRINT_TEXT_FORMAT
,
FTP.STREAM_TRANSFER_MODE
, and
FTP.FILE_STRUCTURE
. The only file types directly supported
are FTP.ASCII_FILE_TYPE
and
FTP.IMAGE_FILE_TYPE
(which is the same as
FTP.BINARY_FILE_TYPE
). Because there are at lest 4
different EBCDIC encodings, we have opted not to provide direct support
for EBCDIC. To transfer EBCDIC and other unsupported file types you
must create your own filter InputStreams and OutputStreams and wrap
them around the streams returned or required by the FTPClient methods.
FTPClient uses the
ToNetASCIIOutputStream
filter streams to provide transparent handling of ASCII files. We will
consider incorporating EBCDIC support if there is enough demand.
FTP.NON_PRINT_TEXT_FORMAT
,
FTP.STREAM_TRANSFER_MODE
, and
FTP.FILE_STRUCTURE
are the only supported formats,
transfer modes, and file structures.
Because the handling of sockets on different platforms can differ
significantly, the FTPClient automatically issues a new PORT command
prior to every transfer requiring that the server connect to the client's
data port. This ensures identical problem-free behavior on Windows, Unix,
and Macintosh platforms. Additionally, it relieves programmers from
having to issue the PORT command themselves and dealing with platform
dependent issues.
Additionally, for security purposes, all data connections to the
client are verified to ensure that they originated from the intended
party (host and port). If a data connection is initiated by an unexpected
party, the command will close the socket and throw an IOException. You
may disable this behavior with
#setRemoteVerificationEnabled.
You should keep in mind that the FTP server may choose to prematurely
close a connection if the client has been idle for longer than a
given time period (usually 900 seconds). The FTPClient class will detect a
premature FTP server connection closing when it receives a
org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLEresponse to a command.
When that occurs, the FTP class method encountering that reply will throw
an
org.apache.commons.net.ftp.FTPConnectionClosedException.
FTPConnectionClosedException
is a subclass of IOException
and therefore need not be
caught separately, but if you are going to catch it separately, its
catch block must appear before the more general IOException
catch block. When you encounter an
org.apache.commons.net.ftp.FTPConnectionClosedException, you must disconnect the connection with
#disconnect to properly clean up the
system resources used by FTPClient. Before disconnecting, you may check the
last reply code and text with
org.apache.commons.net.ftp.FTP#getReplyCode,
org.apache.commons.net.ftp.FTP#getReplyString,
and
org.apache.commons.net.ftp.FTP#getReplyStrings.
You may avoid server disconnections while the client is idle by
periodicaly sending NOOP commands to the server.
Rather than list it separately for each method, we mention here that
every method communicating with the server and throwing an IOException
can also throw a
org.apache.commons.net.MalformedServerReplyException, which is a subclass
of IOException. A MalformedServerReplyException will be thrown when
the reply received from the server deviates enough from the protocol
specification that it cannot be interpreted in a useful manner despite
attempts to be as lenient as possible.
Listing API Examples
Both paged and unpaged examples of directory listings are available,
as follows:
Unpaged (whole list) access, using a parser accessible by auto-detect:
FTPClient f=FTPClient();
f.connect(server);
f.login(username, password);
FTPFile[] files = listFiles(directory);
Paged access, using a parser not accessible by auto-detect. The class
defined in the first parameter of initateListParsing should be derived
from org.apache.commons.net.FTPFileEntryParser:
FTPClient f=FTPClient();
f.connect(server);
f.login(username, password);
FTPListParseEngine engine =
f.initiateListParsing("com.whatever.YourOwnParser", directory);
while (engine.hasNext()) {
FTPFile[] files = engine.getNext(25); // "page size" you want
//do whatever you want with these files, display them, etc.
//expensive FTPFile objects not created until needed.
}
Paged access, using a parser accessible by auto-detect:
FTPClient f=FTPClient();
f.connect(server);
f.login(username, password);
FTPListParseEngine engine = f.initiateListParsing(directory);
while (engine.hasNext()) {
FTPFile[] files = engine.getNext(25); // "page size" you want
//do whatever you want with these files, display them, etc.
//expensive FTPFile objects not created until needed.
}
For examples of using FTPClient on servers whose directory listings
- use languages other than English
- use date formats other than the American English "standard"
MM d yyyy
- are in different timezones and you need accurate timestamps for dependency checking
as in Ant
see
FTPClientConfig.
NOTE: If you experience problems with unwanted firing of
setSoTimeout()
during periods of client inactivity, this can be alleviated by calling
setReaderThread(false)
.
For more details, see
this thread.