This tutorial walks you through steps of developing a Swing-based application that uploads files from local computer to a remote FTP server. The application looks like this:

 SwingFileUploadFTP program

The following diagram describes workflow of the application:

 Swing File Upload FTP application workflow

The Swing client application connects to the server via FTP protocol to transfer files. The FTP library to be used is Apache Commons Net.

The following class diagram depicts how the application is designed:

 SwingFileUploadFTP class diagram

The main classes are:

    • FTPUtility: implements FTP file upload functionality.
    • UploadTask: executes the file upload task in a background thread other than the Swing’s event dispatcher thread (EDT), so the GUI won’t become freezing.
    • SwingFileUploadFTP: assembles user interface of the application. It allows users to specify FTP server information (host, port, username, password and upload destination), choose a file to be uploaded. It shows a progress bar while the upload is taking place.

For the classes JFilePicker and FileTypeFilter, its source code can be obtained from article File picker component in Swing. The FTPException is a custom exception class.

Let’s look at implementation of each main class in details.

 

1. Code of FTPUtility class

package net.codejava.swing.upload.ftp;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

/**
 * A utility class that provides functionality for uploading files to a FTP
 * server.
 * 
 * @author www.codejava.net
 * 
 */
public class FTPUtility {

	private String host;
	private int port;
	private String username;
	private String password;

	private FTPClient ftpClient = new FTPClient();
	private int replyCode;

	private OutputStream outputStream;
	
	public FTPUtility(String host, int port, String user, String pass) {
		this.host = host;
		this.port = port;
		this.username = user;
		this.password = pass;
	}

	/**
	 * Connect and login to the server.
	 * 
	 * @throws FTPException
	 */
	public void connect() throws FTPException {
		try {
			ftpClient.connect(host, port);
			replyCode = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(replyCode)) {
				throw new FTPException("FTP serve refused connection.");
			}

			boolean logged = ftpClient.login(username, password);
			if (!logged) {
				// failed to login
				ftpClient.disconnect();
				throw new FTPException("Could not login to the server.");
			}

			ftpClient.enterLocalPassiveMode();

		} catch (IOException ex) {
			throw new FTPException("I/O error: " + ex.getMessage());
		}
	}

	/**
	 * Start uploading a file to the server
	 * @param uploadFile the file to be uploaded
	 * @param destDir destination directory on the server 
	 * where the file is stored
	 * @throws FTPException if client-server communication error occurred
	 */
	public void uploadFile(File uploadFile, String destDir) throws FTPException {
		try {
			boolean success = ftpClient.changeWorkingDirectory(destDir);
			if (!success) {
				throw new FTPException("Could not change working directory to "
						+ destDir + ". The directory may not exist.");
			}
			
			success = ftpClient.setFileType(FTP.BINARY_FILE_TYPE);			
			if (!success) {
				throw new FTPException("Could not set binary file type.");
			}
			
			outputStream = ftpClient.storeFileStream(uploadFile.getName());
			
		} catch (IOException ex) {
			throw new FTPException("Error uploading file: " + ex.getMessage());
		}
	}

	/**
	 * Write an array of bytes to the output stream.
	 */
	public void writeFileBytes(byte[] bytes, int offset, int length)
			throws IOException {
		outputStream.write(bytes, offset, length);
	}
	
	/**
	 * Complete the upload operation.
	 */
	public void finish() throws IOException {
		outputStream.close();
		ftpClient.completePendingCommand();
	}
	
	/**
	 * Log out and disconnect from the server
	 */
	public void disconnect() throws FTPException {
		if (ftpClient.isConnected()) {
			try {
				if (!ftpClient.logout()) {
					throw new FTPException("Could not log out from the server");
				}
				ftpClient.disconnect();
			} catch (IOException ex) {
				throw new FTPException("Error disconnect from the server: "
						+ ex.getMessage());
			}
		}
	}
}

This utility class is based on the FTP upload functionality described in the tutorial Upload files to a FTP server. However it is designed to allow tracking progress of the upload:

    • The uploadFile() method just initiates a file transfer session with the server (opening an output stream).
    • The writeFileBytes() method will be invoked by the UploadTask to transfer a byte array to the server. This helps the UploadTaskdetermines upload progress and update the progress bar appropriately.

       


2. Code of UploadTask class

package net.codejava.swing.upload.ftp;

import java.io.File;
import java.io.FileInputStream;

import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

/**
 * Executes the file upload in a background thread and updates progress to 
 * listeners that implement the java.beans.PropertyChangeListener interface.
 * @author www.codejava.net
 *
 */
public class UploadTask extends SwingWorker<Void, Void> {
	private static final int BUFFER_SIZE = 4096;
	
	private String host;
	private int port;
	private String username;
	private String password;
	
	private String destDir;
	private File uploadFile;
	
	public UploadTask(String host, int port, String username, String password,
			String destDir, File uploadFile) {
		this.host = host;
		this.port = port;
		this.username = username;
		this.password = password;
		this.destDir = destDir;
		this.uploadFile = uploadFile;
	}

	/**
	 * Executed in background thread
	 */	
	@Override
	protected Void doInBackground() throws Exception {
		FTPUtility util = new FTPUtility(host, port, username, password);
		try {
			util.connect();
			util.uploadFile(uploadFile, destDir);
			
			FileInputStream inputStream = new FileInputStream(uploadFile);
			byte[] buffer = new byte[BUFFER_SIZE];
			int bytesRead = -1;
			long totalBytesRead = 0;
			int percentCompleted = 0;
			long fileSize = uploadFile.length();

			while ((bytesRead = inputStream.read(buffer)) != -1) {
				util.writeFileBytes(buffer, 0, bytesRead);
				totalBytesRead += bytesRead;
				percentCompleted = (int) (totalBytesRead * 100 / fileSize);
				setProgress(percentCompleted);
			}

			inputStream.close();
			
			util.finish();
		} catch (FTPException ex) {
			JOptionPane.showMessageDialog(null, "Error uploading file: " + ex.getMessage(),
					"Error", JOptionPane.ERROR_MESSAGE);			
			ex.printStackTrace();
			setProgress(0);
			cancel(true);			
		} finally {
			util.disconnect();
		}
		
		return null;
	}

	/**
	 * Executed in Swing's event dispatching thread
	 */
	@Override
	protected void done() {
		if (!isCancelled()) {
			JOptionPane.showMessageDialog(null,
					"File has been uploaded successfully!", "Message",
					JOptionPane.INFORMATION_MESSAGE);
		}
	}	
}

By extending the javax.swing.SwingWorker class, the UploadTask executes the file upload in a background thread (code in doInBackground() method) in order to prevent the GUI from freezing (so the GUI can update the progress bar’s state). It notifies listeners about the upload progress by calling the setProgress() method each time a byte array has been transferred. Finally the done() method is invoked when the upload is done, to display a message to the user.


3. Code of SwingFileUploadFTP class

package net.codejava.swing.upload.ftp;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import net.codejava.swing.JFilePicker;

/**
 * A Swing application that uploads files to a FTP server.
 * @author www.codejava.net
 *
 */
public class SwingFileUploadFTP extends JFrame implements
		PropertyChangeListener {

	private JLabel labelHost = new JLabel("Host:");
	private JLabel labelPort = new JLabel("Port:");
	private JLabel labelUsername = new JLabel("Username:");
	private JLabel labelPassword = new JLabel("Password:");
	private JLabel labelUploadPath = new JLabel("Upload path:");

	private JTextField fieldHost = new JTextField(40);
	private JTextField fieldPort = new JTextField(5);
	private JTextField fieldUsername = new JTextField(30);
	private JPasswordField fieldPassword = new JPasswordField(30);
	private JTextField fieldUploadPath = new JTextField(30);

	private JFilePicker filePicker = new JFilePicker("Choose a file: ",
			"Browse");

	private JButton buttonUpload = new JButton("Upload");

	private JLabel labelProgress = new JLabel("Progress:");
	private JProgressBar progressBar = new JProgressBar(0, 100);

	public SwingFileUploadFTP() {
		super("Swing File Upload to FTP server");

		// set up layout
		setLayout(new GridBagLayout());
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.anchor = GridBagConstraints.WEST;
		constraints.insets = new Insets(5, 5, 5, 5);

		// set up components
		filePicker.setMode(JFilePicker.MODE_OPEN);

		buttonUpload.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				buttonUploadActionPerformed(event);
			}
		});

		progressBar.setPreferredSize(new Dimension(200, 30));
		progressBar.setStringPainted(true);

		// add components to the frame
		constraints.gridx = 0;
		constraints.gridy = 0;
		add(labelHost, constraints);

		constraints.gridx = 1;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		constraints.weightx = 1.0;
		add(fieldHost, constraints);

		constraints.gridx = 0;
		constraints.gridy = 1;
		add(labelPort, constraints);

		constraints.gridx = 1;
		add(fieldPort, constraints);

		constraints.gridx = 0;
		constraints.gridy = 2;
		add(labelUsername, constraints);

		constraints.gridx = 1;
		add(fieldUsername, constraints);

		constraints.gridx = 0;
		constraints.gridy = 3;
		add(labelPassword, constraints);

		constraints.gridx = 1;
		add(fieldPassword, constraints);

		constraints.gridx = 0;
		constraints.gridy = 4;
		add(labelUploadPath, constraints);

		constraints.gridx = 1;
		add(fieldUploadPath, constraints);

		constraints.gridx = 0;
		constraints.gridwidth = 2;
		constraints.gridy = 5;
		constraints.anchor = GridBagConstraints.WEST;

		add(filePicker, constraints);

		constraints.gridx = 0;
		constraints.gridy = 6;
		constraints.anchor = GridBagConstraints.CENTER;
		constraints.fill = GridBagConstraints.NONE;
		add(buttonUpload, constraints);

		constraints.gridx = 0;
		constraints.gridy = 7;
		constraints.gridwidth = 1;
		constraints.anchor = GridBagConstraints.WEST;
		add(labelProgress, constraints);

		constraints.gridx = 1;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		add(progressBar, constraints);

		pack();
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	/**
	 * handle click event of the Upload button
	 */
	private void buttonUploadActionPerformed(ActionEvent event) {
		String host = fieldHost.getText();
		int port = Integer.parseInt(fieldPort.getText());
		String username = fieldUsername.getText();
		String password = new String(fieldPassword.getPassword());
		String uploadPath = fieldUploadPath.getText();
		String filePath = filePicker.getSelectedFilePath();

		File uploadFile = new File(filePath);
		progressBar.setValue(0);
		UploadTask task = new UploadTask(host, port, username, password,
				uploadPath, uploadFile);
		task.addPropertyChangeListener(this);
		task.execute();
	}

	/**
	 * Update the progress bar's state whenever the progress of upload changes.
	 */	
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if ("progress" == evt.getPropertyName()) {
			int progress = (Integer) evt.getNewValue();
			progressBar.setValue(progress);
		}
	}

	/**
	 * Launch the application
	 */
	public static void main(String[] args) {
		try {
			// set look and feel to system dependent
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new SwingFileUploadFTP().setVisible(true);
			}
		});
	}
}

This class constructs the user interface and is the main class of the application. It displays a form which allows the user to enter FTP server information (host name, port number, username and password) and upload information (upload path and the file to be uploaded). When the Upload button is clicked, an UploadTask object is created to execute the file upload.

It implements the method propertyChange() from the interface java.beans.PropertyChangeListener in order to be notified about the upload progress, and updates the progress bar’s state accordingly.

For simplicity, the form’s fields are not validated when the Upload button is clicked. So you should add validation code yourself.

 

4. Code of FTPException class

package net.codejava.swing.upload.ftp;

public class FTPException extends Exception {
	public FTPException(String message) {
		super(message);
	}
}

 

5. Testing the application

Run the application and enter the following information:

    • Host: host name or IP address of the FTP server.
    • Port: port number (default is 21 for FTP).
    • Username: name of the FTP account on the server.
    • Password: password of the account.
    • Uploadpath: Path of the directory on the server where the file will be stored.
    • Choosefile: click Browse button to pick up a file to be uploaded.

Click Upload button to start uploading the file. The progress bar is updated continuously during the file transfer:

SwingFileUploadFTP program

When the upload completes, a message dialog appears:

Upload successful message

If the username/password is incorrect, an error message dialog appears like this:

error uploading file message 2

Or if the upload path does not exist on the server:

error uploading file message 1

Download source code and executable jar file of this application in the attachments section. You can also clone the sample project on GitHub.

 

Related Tutorials:

 

Other Java Coding Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (SwingFileUploadFTP.zip)SwingFileUploadFTP.zip[Full source code and executable jar file]274 kB

Add comment

   


Comments 

#25mad2020-03-01 00:02
what is the username and password
Quote
#24Nam2019-05-10 22:50
Quoting Deepak TM:
Hi Nam Ha Minh,

I have an ip address instead of host name, will this code work with ip address ?

Yes, of course, because domain name will be resolved to IP address eventually.
Quote
#23Deepak TM2019-05-10 15:14
Hi Nam Ha Minh,

I have an ip address instead of host name, will this code work with ip address ?
Quote
#22Amit2019-04-08 11:18
This is the very good example
Quote
#21Nam2018-06-15 09:07
Quoting Ganesh Giri:
Can I use in web based Spring and Hibernate Application?

You can re-use the code that deals with FTP, but not the code for Swing GUI.
Quote