tom_corc3
asked on
Basic FTP using Java
I need to write a Java application to upload a textfile (no extension) from my hard disk onto an ftp site (with an ID and password). The fle must be placed on a particular directory on the site .The program also has check another directory on the same site for specific files.
Can this be done easily in Java? Does anybody have the necessary source code?
Can this be done easily in Java? Does anybody have the necessary source code?
Here you are
http://www.cs.albany.edu/~casper/java/
http://www.cs.albany.edu/~casper/java/
Here is some other source code that I have handy. Hope it helps.
//---------FTPSession.java
import java.io.*;
import java.net.*;
import java.util.*;
// This class implements file storage and retrieval using the
// FTP protocol. Your server must support the PASV command
// for this to work.
//
public class FTPSession extends Object
{
public String host; // Host name we connect to
public int port; // port number we connect to, default=21
public String username; // Username to log in with
public String password; // Password to log in with
public String acct; // optional acct for logging in
protected Socket sessionSock; // The control socket
protected DataInputStream inStream;
protected DataOutputStream outStream;
public FTPSession()
{
}
// This should be the most common constructor, it opens up an FTP session
// with the named host using the default FTP port and logs on using
// the username and password.
public FTPSession(String host, String username, String password)
throws IOException
{
this.host = host;
this.port = 21; // default FTP port is 21
this.username = username;
this.password = password;
logon(); // go ahead and log on to the server
}
// Opens up an FTP session with the named host using the default FTP
// port and logs on using the username and password, and account.
// The account field is pretty rare on FTP servers.
public FTPSession(String host, String username, String password,
String acct)
throws IOException
{
this.host = host;
this.port = 21; // default FTP port is 21
this.username = username;
this.password = password;
this.acct = acct;
logon(); // go ahead and log on to the server
}
// Opens up an FTP session with the named host using an alternate
// port number and if logOn is true, logs on using the username and password.
public FTPSession(String host, int port, String username,
String password, boolean logOn)
throws IOException
{
this.host = host;
this.port = port;
if (this.port <= 0) this.port = 21;
this.username = username;
this.password = password;
if (logOn) {
logon();
}
}
// Opens up an FTP session with the named host using an alternate
// port number and if logOn is true, logs on using the username,
// password and account.
public FTPSession(String host, int port, String username,
String password, String acct, boolean logOn)
throws IOException
{
this.host = host;
this.port = port;
if (this.port <= 0) this.port = 21;
this.username = username;
this.password = password;
this.acct = acct;
if (logOn) {
logon();
}
}
// Close down the session
public void close()
throws IOException
{
sessionSock.close();
sessionSock = null;
}
// Connect to the server
public void connect()
throws IOException
{
sessionSock = new Socket(host, port);
inStream = new DataInputStream(
sessionSock.getInputStream ());
outStream = new DataOutputStream(
sessionSock.getOutputStrea m());
}
// Send a command and wait for a response
public String doCommand(String commandString)
throws IOException
{
outStream.writeBytes(comma ndString+" \n");
String response = getResponse();
return response;
}
// Get a response back from the server. Handles multi-line responses
// and returns them as part of the string.
public String getResponse()
throws IOException
{
String response = "";
for (;;) {
String line = inStream.readLine();
if (line == null) {
throw new IOException(
"Bad response from server.");
}
// FTP response lines should at the very least have a 3-digit number
if (line.length() < 3) {
throw new IOException(
"Bad response from server.");
}
response += line + "\n";
// If there isn't a '-' immediately after the number, we've gotten the
// complete response. ('-' is the continuation character for FTP responses)
if ((line.length() == 3) ||
(line.charAt(3) != '-')) return response;
}
}
// Logs on to the FTP server
public void logon()
throws IOException
{
connect();
// After connecting, the FTP server will send a response string. Make
// sure it starts with a '2' (reponses in the 200's are positive
// responses.
String response = getResponse();
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// Send a logon command
response = doCommand("USER "+username);
// If we get a response in the 300's, send a password
if (response.charAt(0) == '3') {
response = doCommand("PASS "+password);
// If we get a response in the 300's on the password command,
// send the account
if (response.charAt(0) == '3') {
response = doCommand("ACCT "+acct);
}
}
// If the last response we got wasn't in the 200's, there was an error
// during the logon.
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
// Creates a data connection to the server by using the PASV command.
// Normally the data connection is set up by the client sending the
// server an address and port number using the PORT command. Unfortunately,
// since an applet cannot listen for incoming connections, we can't work
// that way. The PASV command asks the server to accept a connection.
// The response for the PASV command contains a host address and port
// number in the form h,h,h,h,p,p where h is a byte in the host address
// and p is a byte in the port.
protected synchronized Socket doPasvPort()
throws IOException
{
// Send the PASV command
String response = doCommand("PASV");
// If it wasn't in the 200's, there was an error
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// The pasv response looks like:
// 227 Entering Passive Mode (127,0,0,1,4,160)
// We'll look for the ()'s at the end first
int parenStart = response.lastIndexOf('(');
int parenEnd = response.lastIndexOf(')');
// Make sure they're both there and that the ) comes after the (
if ((parenStart < 0) || (parenEnd < 0) ||
(parenStart >= parenEnd)) {
throw new IOException("PASV response format error");
}
// Extract the address bytes
String pasvAddr = response.substring(parenSt art+1, parenEnd);
// Create a tokenizer to parse the bytes
StringTokenizer tokenizer = new StringTokenizer(pasvAddr, ",");
// Create the array to store the bytes
int[] addrValues = new int[6];
// Parse each byte
for (int i=0; (i < 6) && tokenizer.hasMoreTokens(); i++) {
try {
addrValues[i] = Integer.valueOf(
tokenizer.nextToken()).int Value();
} catch (Exception e) {
throw new IOException(
"PASV response format error");
}
}
// We ignore the host addresses, assuming that the host address is
// the same as the host address we used to connect the first time.
Socket newSock = new Socket(host, (addrValues[4] << 8) +
addrValues[5]);
return newSock;
}
// Fetches a file in binary mode and returns it as an array of bytes
public byte[] get(String remoteFile)
throws IOException
{
return get(remoteFile, true); // default to binary
}
// Fetches a file in binary mode if doBinary is true, or ascii mode if
// it's false, and returns it as an array of bytes.
public synchronized byte[] get(String remoteFile, boolean doBinary)
throws IOException
{
// If transferring in binary mode, send a type command for type I (IMAGE)
if (doBinary) {
String response = doCommand("TYPE I");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// If transferring in ascii mode, send a type command for type A (ASCII)
} else {
String response = doCommand("TYPE A");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
// Set up the data connection
Socket getSock = doPasvPort();
// Tell the server to send the file over
String response = doCommand("RETR "+remoteFile);
// If the request is successful, the server should send a response
// in the 100's and then start sending the file. Once the file is
// sent, it should send a response in the 200's.
// Check for an initial response in the 100's
if (response.charAt(0) != '1') {
getSock.close();
throw new IOException(response);
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
// For binary transfers, read one byte at a time and store it in
// the array.
if (doBinary) {
InputStream in = getSock.getInputStream();
int ch;
while ((ch = in.read()) >= 0) {
out.write(ch);
}
// For ascii transfers, read a line at a time and strip off whatever
// newline we got.
} else {
DataInputStream in = new DataInputStream(
getSock.getInputStream());
PrintStream dataOut = new PrintStream(out);
String line;
while ((line = in.readLine()) != null) {
dataOut.println(line);
}
}
// Close the data connection
getSock.close();
// Make sure we got a response in the 200's saying the transfer was
// successful.
response = getResponse();
if (response.charAt(0) != '2') {
throw new IOException(response);
}
return out.toByteArray();
}
// Stores an array of bytes in the named file using binary mode
public synchronized void put(String remoteFile, byte[] data)
throws IOException
{
put(remoteFile, data, true); // default to binary
}
// Stores an array of bytes in the named file, using binary mode if
// doBinary is true, ascii mode otherwise.
public synchronized void put(String remoteFile, byte[] data,
boolean doBinary)
throws IOException
{
// If transferring in binary mode, send a type command for type I (IMAGE)
if (doBinary) {
String response = doCommand("TYPE I");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// If transferring in ascii mode, send a type command for type A (ASCII)
} else {
String response = doCommand("TYPE A");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
// Open up a data connection
Socket putSock = doPasvPort();
// Tell the server where we want it to store the data we are sending
String response = doCommand("STOR "+remoteFile);
// If the request is successful, the server should send a response
// in the 100's and then start receiving the bytes. Once the data
// connection is closed, it should send a response in the 200's.
if (response.charAt(0) != '1') {
putSock.close();
throw new IOException(response);
}
// If binary mode, just write all the bytes
if (doBinary) {
OutputStream out = putSock.getOutputStream();
out.write(data);
// If ascii mode, write the data a line at a time
} else {
DataInputStream in = new DataInputStream(
new ByteArrayInputStream(data) );
DataOutputStream out = new DataOutputStream(
putSock.getOutputStream()) ;
String line;
while ((line = in.readLine()) != null) {
out.writeBytes(line+"\r");
}
}
putSock.close();
response = getResponse();
// Make sure we got a 200 response
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
}
//---------FTPSession.java
import java.io.*;
import java.net.*;
import java.util.*;
// This class implements file storage and retrieval using the
// FTP protocol. Your server must support the PASV command
// for this to work.
//
public class FTPSession extends Object
{
public String host; // Host name we connect to
public int port; // port number we connect to, default=21
public String username; // Username to log in with
public String password; // Password to log in with
public String acct; // optional acct for logging in
protected Socket sessionSock; // The control socket
protected DataInputStream inStream;
protected DataOutputStream outStream;
public FTPSession()
{
}
// This should be the most common constructor, it opens up an FTP session
// with the named host using the default FTP port and logs on using
// the username and password.
public FTPSession(String host, String username, String password)
throws IOException
{
this.host = host;
this.port = 21; // default FTP port is 21
this.username = username;
this.password = password;
logon(); // go ahead and log on to the server
}
// Opens up an FTP session with the named host using the default FTP
// port and logs on using the username and password, and account.
// The account field is pretty rare on FTP servers.
public FTPSession(String host, String username, String password,
String acct)
throws IOException
{
this.host = host;
this.port = 21; // default FTP port is 21
this.username = username;
this.password = password;
this.acct = acct;
logon(); // go ahead and log on to the server
}
// Opens up an FTP session with the named host using an alternate
// port number and if logOn is true, logs on using the username and password.
public FTPSession(String host, int port, String username,
String password, boolean logOn)
throws IOException
{
this.host = host;
this.port = port;
if (this.port <= 0) this.port = 21;
this.username = username;
this.password = password;
if (logOn) {
logon();
}
}
// Opens up an FTP session with the named host using an alternate
// port number and if logOn is true, logs on using the username,
// password and account.
public FTPSession(String host, int port, String username,
String password, String acct, boolean logOn)
throws IOException
{
this.host = host;
this.port = port;
if (this.port <= 0) this.port = 21;
this.username = username;
this.password = password;
this.acct = acct;
if (logOn) {
logon();
}
}
// Close down the session
public void close()
throws IOException
{
sessionSock.close();
sessionSock = null;
}
// Connect to the server
public void connect()
throws IOException
{
sessionSock = new Socket(host, port);
inStream = new DataInputStream(
sessionSock.getInputStream
outStream = new DataOutputStream(
sessionSock.getOutputStrea
}
// Send a command and wait for a response
public String doCommand(String commandString)
throws IOException
{
outStream.writeBytes(comma
String response = getResponse();
return response;
}
// Get a response back from the server. Handles multi-line responses
// and returns them as part of the string.
public String getResponse()
throws IOException
{
String response = "";
for (;;) {
String line = inStream.readLine();
if (line == null) {
throw new IOException(
"Bad response from server.");
}
// FTP response lines should at the very least have a 3-digit number
if (line.length() < 3) {
throw new IOException(
"Bad response from server.");
}
response += line + "\n";
// If there isn't a '-' immediately after the number, we've gotten the
// complete response. ('-' is the continuation character for FTP responses)
if ((line.length() == 3) ||
(line.charAt(3) != '-')) return response;
}
}
// Logs on to the FTP server
public void logon()
throws IOException
{
connect();
// After connecting, the FTP server will send a response string. Make
// sure it starts with a '2' (reponses in the 200's are positive
// responses.
String response = getResponse();
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// Send a logon command
response = doCommand("USER "+username);
// If we get a response in the 300's, send a password
if (response.charAt(0) == '3') {
response = doCommand("PASS "+password);
// If we get a response in the 300's on the password command,
// send the account
if (response.charAt(0) == '3') {
response = doCommand("ACCT "+acct);
}
}
// If the last response we got wasn't in the 200's, there was an error
// during the logon.
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
// Creates a data connection to the server by using the PASV command.
// Normally the data connection is set up by the client sending the
// server an address and port number using the PORT command. Unfortunately,
// since an applet cannot listen for incoming connections, we can't work
// that way. The PASV command asks the server to accept a connection.
// The response for the PASV command contains a host address and port
// number in the form h,h,h,h,p,p where h is a byte in the host address
// and p is a byte in the port.
protected synchronized Socket doPasvPort()
throws IOException
{
// Send the PASV command
String response = doCommand("PASV");
// If it wasn't in the 200's, there was an error
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// The pasv response looks like:
// 227 Entering Passive Mode (127,0,0,1,4,160)
// We'll look for the ()'s at the end first
int parenStart = response.lastIndexOf('(');
int parenEnd = response.lastIndexOf(')');
// Make sure they're both there and that the ) comes after the (
if ((parenStart < 0) || (parenEnd < 0) ||
(parenStart >= parenEnd)) {
throw new IOException("PASV response format error");
}
// Extract the address bytes
String pasvAddr = response.substring(parenSt
// Create a tokenizer to parse the bytes
StringTokenizer tokenizer = new StringTokenizer(pasvAddr, ",");
// Create the array to store the bytes
int[] addrValues = new int[6];
// Parse each byte
for (int i=0; (i < 6) && tokenizer.hasMoreTokens();
try {
addrValues[i] = Integer.valueOf(
tokenizer.nextToken()).int
} catch (Exception e) {
throw new IOException(
"PASV response format error");
}
}
// We ignore the host addresses, assuming that the host address is
// the same as the host address we used to connect the first time.
Socket newSock = new Socket(host, (addrValues[4] << 8) +
addrValues[5]);
return newSock;
}
// Fetches a file in binary mode and returns it as an array of bytes
public byte[] get(String remoteFile)
throws IOException
{
return get(remoteFile, true); // default to binary
}
// Fetches a file in binary mode if doBinary is true, or ascii mode if
// it's false, and returns it as an array of bytes.
public synchronized byte[] get(String remoteFile, boolean doBinary)
throws IOException
{
// If transferring in binary mode, send a type command for type I (IMAGE)
if (doBinary) {
String response = doCommand("TYPE I");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// If transferring in ascii mode, send a type command for type A (ASCII)
} else {
String response = doCommand("TYPE A");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
// Set up the data connection
Socket getSock = doPasvPort();
// Tell the server to send the file over
String response = doCommand("RETR "+remoteFile);
// If the request is successful, the server should send a response
// in the 100's and then start sending the file. Once the file is
// sent, it should send a response in the 200's.
// Check for an initial response in the 100's
if (response.charAt(0) != '1') {
getSock.close();
throw new IOException(response);
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
// For binary transfers, read one byte at a time and store it in
// the array.
if (doBinary) {
InputStream in = getSock.getInputStream();
int ch;
while ((ch = in.read()) >= 0) {
out.write(ch);
}
// For ascii transfers, read a line at a time and strip off whatever
// newline we got.
} else {
DataInputStream in = new DataInputStream(
getSock.getInputStream());
PrintStream dataOut = new PrintStream(out);
String line;
while ((line = in.readLine()) != null) {
dataOut.println(line);
}
}
// Close the data connection
getSock.close();
// Make sure we got a response in the 200's saying the transfer was
// successful.
response = getResponse();
if (response.charAt(0) != '2') {
throw new IOException(response);
}
return out.toByteArray();
}
// Stores an array of bytes in the named file using binary mode
public synchronized void put(String remoteFile, byte[] data)
throws IOException
{
put(remoteFile, data, true); // default to binary
}
// Stores an array of bytes in the named file, using binary mode if
// doBinary is true, ascii mode otherwise.
public synchronized void put(String remoteFile, byte[] data,
boolean doBinary)
throws IOException
{
// If transferring in binary mode, send a type command for type I (IMAGE)
if (doBinary) {
String response = doCommand("TYPE I");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
// If transferring in ascii mode, send a type command for type A (ASCII)
} else {
String response = doCommand("TYPE A");
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
// Open up a data connection
Socket putSock = doPasvPort();
// Tell the server where we want it to store the data we are sending
String response = doCommand("STOR "+remoteFile);
// If the request is successful, the server should send a response
// in the 100's and then start receiving the bytes. Once the data
// connection is closed, it should send a response in the 200's.
if (response.charAt(0) != '1') {
putSock.close();
throw new IOException(response);
}
// If binary mode, just write all the bytes
if (doBinary) {
OutputStream out = putSock.getOutputStream();
out.write(data);
// If ascii mode, write the data a line at a time
} else {
DataInputStream in = new DataInputStream(
new ByteArrayInputStream(data)
DataOutputStream out = new DataOutputStream(
putSock.getOutputStream())
String line;
while ((line = in.readLine()) != null) {
out.writeBytes(line+"\r");
}
}
putSock.close();
response = getResponse();
// Make sure we got a 200 response
if (response.charAt(0) != '2') {
throw new IOException(response);
}
}
}
ASKER
Hi Manhthang
Thanks for the code.
Is this suitable for an NT workstation and server and a Windows 98 machine using dial up networking.
Should I manually start up a dial up networking session before running the program?
Also a comment says 'Your server must support the PASV command'. How can I find this out? I don't know what the PASV command is.
Thanks
Tom
Thanks for the code.
Is this suitable for an NT workstation and server and a Windows 98 machine using dial up networking.
Should I manually start up a dial up networking session before running the program?
Also a comment says 'Your server must support the PASV command'. How can I find this out? I don't know what the PASV command is.
Thanks
Tom
ASKER
Hi there again manhthang
Forgive my ignorance about ftp.
Can you give me examples of these parameters into the constructors:
-String host ("ftp://10.24.34.198" ???)
-acct ????
-logon - What effect does true and false have here?
Thanks
Tom
Forgive my ignorance about ftp.
Can you give me examples of these parameters into the constructors:
-String host ("ftp://10.24.34.198" ???)
-acct ????
-logon - What effect does true and false have here?
Thanks
Tom
ASKER
Adjusted points from 200 to 300
ASKER
Does anyone know how to do this:
I open up an ftp link via dial up networking. The ftp site is only available by dialing this particular phone number. Dial up networking provides the ID and password necessary to connect to the site. When the dial up link is up I can browse to the site in my IE5 browser.
However in my Java program I get an 'Unknown Host Exception' on this line:
Socket sessionSock;
sessionSock = new Socket(host, port);
Here host is something like "ftp://100.100.100.100" and port is 21.
Has anyone got any ideas what I have to do to connect in Java?
Thanks
Tom
I open up an ftp link via dial up networking. The ftp site is only available by dialing this particular phone number. Dial up networking provides the ID and password necessary to connect to the site. When the dial up link is up I can browse to the site in my IE5 browser.
However in my Java program I get an 'Unknown Host Exception' on this line:
Socket sessionSock;
sessionSock = new Socket(host, port);
Here host is something like "ftp://100.100.100.100" and port is 21.
Has anyone got any ideas what I have to do to connect in Java?
Thanks
Tom
Sorry Tom about the late reply.
Yes this code can be used on all the platforms you mentioned because it's 100% Java. You need to resort to other programs (may be JNI) to invoke dialup networking inside your code. After that, use:
FTPSession sess = new FTPSession(
"10.24.34.198",
"anonymous", "tom@", true);
The flag logon is to log on to the server using the user name and password, after having opened an ftp session with the server. Usually if you put logon as false, you only get as far as the prompt for user name and password, and you will need to manually enter your name and password at the prompt.
The PASV command is like the PORT command, used to force the server to create a listen socket and hence establish a connection with the client.
To see whether this is available on your FTP server, open your server and type ? for a list of all available commands.
I think you got the error because you included "ftp://" at the front of your host string.
Hope this helps.
Yes this code can be used on all the platforms you mentioned because it's 100% Java. You need to resort to other programs (may be JNI) to invoke dialup networking inside your code. After that, use:
FTPSession sess = new FTPSession(
"10.24.34.198",
"anonymous", "tom@", true);
The flag logon is to log on to the server using the user name and password, after having opened an ftp session with the server. Usually if you put logon as false, you only get as far as the prompt for user name and password, and you will need to manually enter your name and password at the prompt.
The PASV command is like the PORT command, used to force the server to create a listen socket and hence establish a connection with the client.
To see whether this is available on your FTP server, open your server and type ? for a list of all available commands.
I think you got the error because you included "ftp://" at the front of your host string.
Hope this helps.
ASKER
Thanks to both of you mplungjan and manhthang.
manhthang dropping the "ftp" worked.
mplungjan I am successfully using the Kasper classes and I am able to transfer file to and from the siteHowever th list and nlst copmmands return null pointer exceptions. Do you know why?
Here are the details:
500 Invalid PORT Command.
java.lang.NullPointerExcep tion
at kasper.net.ftp.FTPClient.nlst(FTPClient.java, Comp
at kasper.net.ftp.FTPClient.nlst(FTPClient.java)
at FTPTestList.main(FTPTestLi st.java, Compiled Code)
Thanks
Tom
manhthang dropping the "ftp" worked.
mplungjan I am successfully using the Kasper classes and I am able to transfer file to and from the siteHowever th list and nlst copmmands return null pointer exceptions. Do you know why?
Here are the details:
500 Invalid PORT Command.
java.lang.NullPointerExcep
at kasper.net.ftp.FTPClient.nlst(FTPClient.java, Comp
at kasper.net.ftp.FTPClient.nlst(FTPClient.java)
at FTPTestList.main(FTPTestLi
Thanks
Tom
ASKER
Adjusted points from 300 to 500
ASKER
PLEASE
help me on this. I want to set the timeout for the call:
client.retr(filename)
if the file name does exist the program hangs. As the listing is unavailable (see my previous comment) I need to look for files that may not be there.
If I could set the timeout then it would be OK - ie move to the next file in the list.
Thanks in advance
Tom
help me on this. I want to set the timeout for the call:
client.retr(filename)
if the file name does exist the program hangs. As the listing is unavailable (see my previous comment) I need to look for files that may not be there.
If I could set the timeout then it would be OK - ie move to the next file in the list.
Thanks in advance
Tom
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Comment accepted as answer
ASKER
Thanks to both of you manhthang and mplungjan.
If I could split the 500 points between the 2 of you I would.
I eventually used mostly mplungjan's solution.
If either of you have an answer to the question of getting a complete directory listing on the remote server (other than Kaspers list or nlist) I'd appreciate if you you could mail me on tom_corc@homail.com
If I could split the 500 points between the 2 of you I would.
I eventually used mostly mplungjan's solution.
If either of you have an answer to the question of getting a complete directory listing on the remote server (other than Kaspers list or nlist) I'd appreciate if you you could mail me on tom_corc@homail.com
You could... Next time ask Customer services to help :-)
I will be back from vacation in two weeks - I will attempt to help you then if you have not found an answer in the mean time...
Michel
I will be back from vacation in two weeks - I will attempt to help you then if you have not found an answer in the mean time...
Michel
Can you do a list from a plain ftp session???
Michel
Michel
I am looking for one for you
Michel