Of course! Let's dive into using FTP in Java with the Apache Commons Net library. This is the most common and robust way to handle FTP operations in Java.
Why Apache Commons Net?
While Java has a built-in java.net.FTPClient, it's notoriously difficult to use, buggy, and lacks support for crucial features like:
- FTPES (FTP over explicit SSL/TLS)
- SFTP (SSH File Transfer Protocol - Note: This is different from FTPS)
- Easy handling of passive mode.
- Clean, high-level API for common operations.
The Apache Commons Net library solves all these problems and provides a reliable, well-documented, and feature-rich FTP client.
Step 1: Add the Dependency
First, you need to add the Apache Commons Net library to your project. Choose the method that works for your build tool.
Using Maven (pom.xml)
Add this dependency to your pom.xml file:
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version> <!-- Check for the latest version -->
</dependency>
Using Gradle (build.gradle)
Add this dependency to your build.gradle file:
implementation 'commons-net:commons-net:3.9.0' // Check for the latest version
Step 2: Core FTP Operations with Java Code
Here are the most common FTP operations explained with code examples.
Connecting and Logging In
This is the first step. You create a client, connect to the server, and log in with your credentials.
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import java.io.IOException;
public class FtpExample {
public static void main(String[] args) {
String server = "ftp.example.com";
int port = 21;
String user = "username";
String pass = "password";
FTPClient ftpClient = new FTPClient();
try {
// 1. Connect to the server
System.out.println("Connecting to " + server);
ftpClient.connect(server, port);
int replyCode = ftpClient.getReplyCode();
// 2. Check the connection reply code
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("FTP server refused connection.");
return;
}
// 3. Login to the server
boolean loginSuccess = ftpClient.login(user, pass);
if (!loginSuccess) {
System.out.println("Could not login to the server.");
return;
}
System.out.println("Login successful.");
// 4. Set file type to BINARY (important for non-text files)
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// --- Now you can perform other operations ---
// listFilesExample(ftpClient);
// uploadFileExample(ftpClient);
// downloadFileExample(ftpClient);
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
// 5. Logout and disconnect
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Listing Files in a Directory
To see what's on the server, you can list the files in the current or a specified directory.
import org.apache.commons.net.ftp.FTPFile;
import java.io.IOException;
public static void listFilesExample(FTPClient ftpClient) throws IOException {
System.out.println("Listing files from the current directory...");
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
for (FTPFile file : files) {
System.out.println(file.getName());
}
} else {
System.out.println("No files found.");
}
}
Uploading a File
Uploading a file involves reading from a local File or InputStream and writing it to the server.
import java.io.FileInputStream;
import java.io.IOException;
public static void uploadFileExample(FTPClient ftpClient) throws IOException {
String localFilePath = "C:/local/path/to/your/file.txt";
String remoteFilePath = "/remote/path/on/server/file.txt";
try (InputStream inputStream = new FileInputStream(localFilePath)) {
System.out.println("Uploading file to: " + remoteFilePath);
boolean done = ftpClient.storeFile(remoteFilePath, inputStream);
if (done) {
System.out.println("The file was uploaded successfully.");
} else {
System.out.println("Could not upload the file.");
}
}
}
Downloading a File
Downloading is the reverse of uploading. You read from the server's InputStream and write to a local File or OutputStream.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public static void downloadFileExample(FTPClient ftpClient) throws IOException {
String remoteFilePath = "/remote/path/on/server/file.txt";
String localFilePath = "C:/local/path/to/save/file.txt";
try (OutputStream outputStream = new FileOutputStream(localFilePath)) {
System.out.println("Downloading file from: " + remoteFilePath);
boolean success = ftpClient.retrieveFile(remoteFilePath, outputStream);
if (success) {
System.out.println("The file was downloaded successfully.");
} else {
System.out.println("Could not download the file.");
}
}
}
Creating Directories
You can create directories on the server.
import java.io.IOException;
public static void createDirectoryExample(FTPClient ftpClient) throws IOException {
String dirToCreate = "/new/directory";
System.out.println("Creating directory: " + dirToCreate);
boolean success = ftpClient.makeDirectory(dirToCreate);
if (success) {
System.out.println("Directory created successfully.");
} else {
System.out.println("Failed to create directory. Reply: " + ftpClient.getReplyString());
}
}
Step 3: Handling Security (FTPS)
For modern applications, you should always use a secure version of FTP. FTPS (FTP over SSL/TLS) is the standard. Apache Commons Net supports both Implicit and Explicit FTPS.
Implicit FTPS (Older, less common)
This was the original way to secure FTP. The entire connection is encrypted from the start.
// Inside your main method, after creating the FTPClient ftpClient = new FTPSClient(true); // 'true' for Implicit FTPS // The rest of the connection code remains the same
Explicit FTPS (Recommended, modern)
This is the modern standard. The client connects normally on an unencrypted port and then issues a AUTH TLS command to "upgrade" the connection to be secure. This is more flexible as it allows fallback to unencrypted FTP if the server doesn't support it.
// Inside your main method, after creating the FTPClient
ftpClient = new FTPSClient(); // Default is Explicit FTPS
// --- Modify the connection code ---
try {
System.out.println("Connecting to " + server);
ftpClient.connect(server, port);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("FTP server refused connection.");
return;
}
// Enter local passive mode. This is crucial for firewalls.
ftpClient.enterLocalPassiveMode();
// Before login, set up the security
// Set protection buffer size (optional, but recommended)
ftpClient.execPBSZ(0);
// Set data protection level to Private (encrypted)
ftpClient.execPROT("P");
// Now, login as you normally would
boolean loginSuccess = ftpClient.login(user, pass);
// ... rest of the code
Key Security Settings for Explicit FTPS:
ftpClient.enterLocalPassiveMode();: This is very important. It tells the client to use passive mode, which works much better through firewalls and NATs.ftpClient.execPBSZ(0);: Sets the protection buffer size to 0, which is a required step for many servers.ftpClient.execPROT("P");: This is the crucial command that tells the server to switch to a private (encrypted) data channel.
Complete Example: Secure FTPS Upload
Here is a full, runnable example that connects securely, lists files, and uploads a file.
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPSClient;
import org.apache.commons.net.ftp.FTPReply;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class SecureFtpUpload {
public static void main(String[] args) {
String server = "ftp.yourserver.com";
int port = 21;
String user = "your_username";
String pass = "your_password";
String localFilePath = "C:/temp/report.pdf";
String remoteFilePath = "/reports/report.pdf";
FTPSClient ftpsClient = new FTPSClient();
try (InputStream inputStream = new FileInputStream(localFilePath)) {
// 1. Connect to the server
System.out.println("Connecting to " + server);
ftpsClient.connect(server, port);
int replyCode = ftpsClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("FTP server refused connection.");
return;
}
// 2. Enter passive mode
ftpsClient.enterLocalPassiveMode();
// 3. Configure security for Explicit FTPS
ftpsClient.execPBSZ(0);
ftpsClient.execPROT("P");
// 4. Login
if (!ftpsClient.login(user, pass)) {
System.out.println("Could not login to the server.");
return;
}
System.out.println("Login successful.");
// 5. Set file type to BINARY
ftpsClient.setFileType(FTP.BINARY_FILE_TYPE);
// 6. Upload the file
System.out.println("Uploading file to: " + remoteFilePath);
boolean done = ftpsClient.storeFile(remoteFilePath, inputStream);
if (done) {
System.out.println("The file was uploaded successfully.");
} else {
System.out.println("Could not upload the file. Server reply: " + ftpsClient.getReplyString());
}
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
// 7. Logout and disconnect
if (ftpsClient.isConnected()) {
ftpsClient.logout();
ftpsClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Important: SFTP vs. FTPS
It's a common point of confusion. They are different protocols:
| Feature | FTP (File Transfer Protocol) | FTPS (FTP Secure) | SFTP (SSH File Transfer Protocol) |
|---|---|---|---|
| Protocol | Separate TCP control & data channels. | FTP over SSL/TLS (Secure Sockets Layer / Transport Layer Security). | Part of the SSH (Secure Shell) protocol. Runs over a single channel. |
| Port | 21 (Control), 20 (Data) | 990 (Implicit), 21 (Explicit) | 22 |
| How it Works | Unencrypted by default. | Encrypts the control and data channels. | Encrypts the commands and data within the SSH session. |
| Library | java.net.FTPClient or Apache Commons Net FTP/FTPS clients. |
Apache Commons Net FTPSClient. |
JSch, Apache Mina SSHD, etc. (Requires a different library). |
| Use Case | Legacy, unsecure transfers. Avoid for new projects. | Secure transfer, often used with legacy systems that don't support SFTP. | Modern, secure standard. The recommended choice if the server supports it. |
If your server supports SFTP, it is generally the preferred protocol due to its simplicity (single port) and robust security model. You would use a library like JSch for SFTP in Java.
