Connecting to an FTP server with edtFTPj/Free is simply a matter of:
1. Creating an object
FileTransferClient ftp =
new FileTransferClient();
2. Setting the remote host and user credentials
ftp.setRemoteHost(host);
ftp.setUserName(username);
ftp.setPassword(password);
3. Calling the
connect() method, which connects to the server and logs in.
ftp.connect();
4. Logging out and closing the connection.
ftp.disconnect();
The connect() call will return when successfully connected and logged in, or throw an exception if it fails to
connect or log in.
Note that the automatic login can be disabled using the advanced settings,
which must be obtained via .
ftp.getAdvancedFTPSettings().setAutoLogin(false);
If autologin is disabled,
must be be used to log into the server after connect() has been called (and prior to any remote operations
being performed):
ftp.connect();
ftp.manualLogin();
There
are two basic ways to get a list of the files in a particular directory
on an FTP server. The simpler way gets the names of the files using the
method:
string[] files = ftp.directoryNameList();
This
results in the files array containing the name of the files and
directories in the current working directory on the server.
FTP
servers can return more information than just the names of the files
and directories. This information can be returned as an array of
strings by using an overloaded
method. The 'full' boolean flag must be set to true to get the full
listing:
string[] descriptions = ftp.directoryNameList("mydirname", true);
For
convenience, the detailed file and directory information can be
interpreted and returned as an object, in the
method:
FTPFile[] files =
ftp.directoryList();
This
method returns an array of objects containing information
about the files in the directory - details such as the size of the file
and whether or not it is a directory.
If
a listing of a directory other than the current working directory is
required it is recommended that the remote working directory be changed
to that directory, as described in .
The relative or absolute path may be passed to either method, but
some FTP servers do not support this feature. In these cases changing
directories should work.
Changing
locale
Sometimes
the directoryList() method will fail with a
ParseException, citing a date string that it cannot interpret. This is
often because the FTP server is in a different locale to the client.
It may be returning month names that cannot be understood in the
client's locale. For example, an FTP server in a German locale will
return German month names, which cannot be interpreted by a client in a
locale that uses English. To solve this, the server's locale should be
set in the client, before connecting, via the
method:
Locale[] locales = new Locale[2];
locales[0] = = Locale.GERMAN;
locales[1] = Locale.getDefault();
ftp.getAdvancedFTPSettings().setParserLocales(locales);
While you are connected to an FTP server, the server keeps track of your working directory.
The server assumes you are referring to this directory whenever you
perform a file operation without specifying an absolute path. In fact
many FTP servers do not support the use of absolute paths.
The current working directory is available by calling the method:
string directory =
;
This may be changed using:
ftp.;
Or to simply go up to the parent directory:
ftp.;
upload, download and delete a file
|
|
|
|
|
Uploading, downloading and deletion of files is all done through simple method calls on the
Uploading Files
Uploading of a file is done by the following method-call:
ftp.;
This
method uploads the file specified by the first argument and saves it on
the server with the name specified by the second argument. If the file
is already present on the server then it is usually overwritten, though
this depends on the server configuration.
File appending is also supported, whereby the contents of the local file are appended to the end of
the remote file. Appending is done by passing a third parameter to the uploadFile() method:
ftp.;
Downloading Files
Downloading of a file is done by the following method-call:
ftp.;
This method downloads the file specified by the second argument and saves it locally with the name specified by the first
argument. If the file is already present on the local storage medium then it is overwritten.
A remote file can also be downloaded into memory as a byte
array:
ftp.;
Deleting Files
A file may be deleted by calling the method.
Notes:
(1) It is often useful to use streams to transfer data directly to and from memory. The topic explains how to do this.
Files
and data can be transferred in two different modes with all client
classes - binary mode and ASCII mode. The transfer mode should always be
set explicitly to ensure the correct mode is used.
Binary mode is the default for
.
ASCII
Mode
ASCII mode should be used when
end-of-line character translation is required. When using ASCII mode,
files are not
transferred byte-for-byte. Instead, the newline
character(s) on the source platform (e.g. in Windows, CR+LF) are
replaced with the newline character(s) on the target platform (e.g. on
Unix, LF). This means the source file may not be the same size as the
end result if the platforms differ. If binary mode is used, for
example, to transfer Unix text files to a Windows platform, many
Windows text editors will not recognize the Unix newline characters,
and the file will be difficult to read. To use ASCII mode, the
method should be used, supplying the ASCII type as shown.
ftp.;
It's important to note that it is often acceptable to transfer text
files in binary mode since most modern text editors are able to deal
with UNIX and Windows end-of-line characters interchangably.
Furthermore, text files that appear to be ASCII files often
contain "extended ASCII" characters which may be incompatible between
different platforms. It is therefore advisable to use binary
mode
unless end-of-line character translation is definitely required.
Binary
Mode
Binary mode (a.k.a. image mode)
should be used whenever no end-of-line translation is required.
In
binary mode, the file is transferred byte-for-byte, i.e. an exact copy
of the file or data is transferred. Typically, binary mode is used for
files such as executables, compressed files, media files and non-text
document formats such as OpenOffice or Microsoft Office files. To use
binary mode, the
method should be used, supplying the BINARY type as shown.
ftp.;
use active or passive mode |
|
|
|
|
In
the FTP protocol, data transfers are made on a different
connection to the control connection - and a new connection is made for
each data transfer or directory listing.
Data connections
can be made in two different ways - the server initiating the
connection (active mode) or the client initiating the connection
(passive mode). For more discussion on connect modes, see
The connect mode has certain implications for FTP'ing through firewalls. If problems are experienced
using one mode, the alternative mode should be tried.
Active
Mode
To use active mode, the
advanced settings object must be obtained via ,
followed by ,
supplying the ACTIVE mode as shown:
ftp.getAdvancedFTPSettings().setConnectMode(FTPConnectMode.ACTIVE);
In active mode, the client supplies the port number to which the server connects.
This is normally a random port, but a port range can be specified (for example a
permissable range that is configured in a firewall). Use the
method to set the range, e.g.
ftp.getAdvancedFTPSettings().setActivePortRange(61500, 61510);
The port number being sent to the server can be found from
the log file (in DEBUG mode), looking for the PORT command, e.g.
PORT 151,134,10,195,240,68
The first four numbers are the IP address, and the last two form the port number. To calculate the port number
that the server will try to connect to, multiple the first port number by 256 (2^8), and then add the second port number.
In the example it will be 240*(2^8) + 68, yielding a port number of 61508.
ASCII
Mode
To use passive mode, the
method should be used, supplying the PASV type as shown.
ftp.getAdvancedFTPSettings().setConnectMode(FTPConnectMode.PASV);
If
problems are being experienced with file transfers and directory
listings (both of which use a new data connection each time), it is likely that a
firewall is preventing the creation of the data connection. Try
swapping from active to passive modes, or vice versa.
transfer using FTP streams |
|
|
|
|
One
of the advantages of integrating FTP functionality directly into a
product rather than using stand-alone FTP applications is that data can
be transferred directly to and from memory. This is particularly useful
when transferring dynamic content needs, such as the results of
database queries and other application data.
allows users to use InputStreams and OutputStreams to read and write to FTP servers, in the same
way that a file or socket can be read from or written to. This is done using
and methods.
To upload a string:
string s = "Hello world";
OutputStream out = ftp.uploadStream("Hello.txt");
try {
out.write(s.getBytes());
}
finally {
out.close();
}
It is essential to close the stream before performing any other FTP operations, as this completes the transfer.
Similarly, to download from an FTP server, an InputStream is used. This can be read and written anywhere:
StringBuffer s = new StringBuffer();
InputStream in = ftp.downloadStream("Hello.txt");
try {
int ch = 0;
while ((ch = in.read()) >= 0) {
s.append((char)ch);
}
}
finally {
in.close();
}
Again, it is essential to close the stream before performing any other FTP operations.
monitor transfers and commands
|
|
|
|
|
It
can be very useful to be able to monitor file transfers, that is, to
receive programmatic feedback on how the transfer is progressing.
Similarly, it can be useful to obtain the commands that are being sent
back and forth.
The
interface is used for this purpose. Typically, the developer
implements this interface in their own class (perhaps as an anonymous
class). An instance is set via ,
and once the transfer begins, the instance is notified of the start and
end of the transfer, as well as periodically
during the transfer of how many bytes have been transferred so far. The
commands sent back and forth to the server are also available.
The frequency of notifications of bytes transferred is controlled in the ,
via , which takes the number of bytes in between callbacks.
Note that this value must be greater than
the transfer buffer size, which can be changed via .
This is because for efficiency, checks for the notification interval are only performed after each buffer has been transferred.
pause and resume transfers
|
|
|
|
|
At times network connections fail or processes are restarted,
interrupting transfers. Also, it is sometimes necessary to terminate
transfers, particularly for larger files that take a long time to
transfer.
In
these cases, it is often desirable to resume transfers rather than
starting them from scratch - especially for large files. This means
only the remaining part of the file is subsequently uploaded or
downloaded.
Please note
that resume is only supported for binary mode transfers. Because of line terminator
translations, ASCII mode resumes are inpractical.
Invoking
will cancel the currently executing transfer. To be able to call this method during a
transfer will require a separate thread. Once this method is called,
the transfer will cease once the current transfer buffer is emptied:
ftp.;
// called from
a different thread
Cancelling
a transfer may leave the connection to the server in an inconsistent
state. After cancelling a transfer, it may be necessary to quit and
reconnect to the server.
Once
a transfer has been cancelled
or has been interrupted, it can be resumed to complete the
transfer. For resuming
both uploads and downloads, it relies on
examining the partially downloaded or uploaded file to see how many
bytes remain to be transferred. The remaining bytes are then appended
to the partial file. To perform a resume, simply upload or download the file again, supplying
the parameter.
ftp.download(localFilename, remoteFilename, WriteMode.RESUME);
Because
resuming relies only on the size of the partially downloaded or
uploaded file, it does not matter how long ago the transfer failed or
was terminated. As long as the partially transferred file is still
available (and of course the original file to be transferred
has not changed) , resuming the transfer will work correctly.
Often, it can be very helpful to
look at edtFTPj/Free's extensive logging output if any
problems are experienced communicating with FTP servers. edtFTPj/Free
has a powerful logging API modelled on the popular log4j library
– in fact full integration with log4j is supported.
All commands sent to the FTP server
and subsequent replies are logged, and can be made
available on the console or directed to a log file. Much other useful
information is also logged.
Statements within edtFTPj/Free are
logged at different levels, ranging from least verbose (FATAL), to most
verbose (DEBUG). Intermediate levels are ERROR, WARN, and
INFO. An overall level can be set for the library, and all statements up to and
including that level will be outputted.
For example, if the overall level
is set to INFO
then FATAL, ERROR, WARN
and INFO
log statements will be outputted, but DEBUG
statements
will not be.
There are also two additional
levels that can be conveniently used - OFF which means no
logging will occur, and ALL which means all log statements will be
outputted, no matter what
level they are. The ALL
level is actually an additional level which is used for extremely
verbose
output - so when the level is set to ALL more log statements may be
outputted than at DEBUG.
Logging levels are encapsulated in the
class. For example, the WARN level is represented by
Level.WARN.
By default, the log level is
switched to OFF, so that no logging will appear.
The log level can be changed in two ways. Firstly, it can be changed
explicitly by calling the
method on the
class. For example:
Logger.(Level.);
will set the global logging level
to DEBUG.
A System property, edtftp.log.level,
can also
be used to set the logging level. For example, using the -D option to
set an application's System property, you could
use:
java -Dedtftp.log.level=INFO
com.mypackage.myclass
Using edtFTPj/Free's logging in your
own application is very similar to using log4j. A logger is created,
and its methods used to write logging information. Rather than use the
Level class, the Logger class has convenience methods for logging at
each level. An example is shown below:
Logger log =
Logger.getLogger(MyClass.class);
log.info("Connecting to server " +
host);
Logging
to a file
As noted, all logging by default
goes to standard output. A
must be added if logging is to go to a file (and this will disable
logging to standard out). An example is shown below:
Logger.(new
FileAppender(myLogFileName));
Now all logging output will go to
the FileAppender's file, and no logging will go to standard output.
Multiple FileAppenders can be added. If the
is added to the Logger as well, logging will be directed to the file
and to standard output.
Log4j
integration
Full integration with log4j is possible. A System property, edtftp.log.log4j,
is used to indicate that log4j integration should be attempted. It must
be set to “true”. Also, the log4j jar file must be
available in the CLASSPATH. Once this is done all logging calls are
directed via log4j, using reflection, and the standard log4j settings are used. More details on
log4j can be found at the log4j site listed in the references.