在Java开发中,将文件上传到FTP服务器是一个常见的任务,通常用于文件备份、数据共享或资源管理等功能,实现这一功能主要依赖于Java内置的org.apache.commons.net.ftp包或第三方库如JSch(针对SFTP),以下是详细的实现步骤和代码示例,帮助开发者快速掌握FTP文件上传的核心逻辑。

准备工作
-
添加依赖
如果使用Apache Commons Net库,需在pom.xml中添加Maven依赖:<dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.9.0</version> </dependency>对于Gradle项目,可在
build.gradle中配置:implementation 'commons-net:commons-net:3.9.0'
-
FTP服务器信息
确保已获取FTP服务器的地址、端口、用户名、密码及目标上传路径。- 服务器地址:
ftp.example.com - 端口:
21(默认) - 用户名:
ftpuser - 密码:
password - 目标路径:
/upload/
- 服务器地址:
核心代码实现
以下是完整的Java代码示例,包含FTP连接、文件上传及资源释放逻辑:

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import java.io.FileInputStream;
import java.io.IOException;
public class FtpUploadUtil {
public static void main(String[] args) {
String server = "ftp.example.com";
int port = 21;
String username = "ftpuser";
String password = "password";
String localFilePath = "C:/localfile.txt";
String remoteFilePath = "/upload/localfile.txt";
FTPClient ftpClient = new FTPClient();
try {
// 1. 连接FTP服务器
ftpClient.connect(server, port);
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
throw new IOException("FTP server refused connection.");
}
// 2. 登录FTP服务器
if (!ftpClient.login(username, password)) {
throw new IOException("FTP login failed.");
}
// 3. 设置文件传输模式为二进制(避免文本文件损坏)
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// 4. 进入远程目录
String remoteDir = remoteFilePath.substring(0, remoteFilePath.lastIndexOf('/'));
if (!remoteDir.isEmpty() && !ftpClient.changeWorkingDirectory(remoteDir)) {
throw new IOException("Failed to change remote directory: " + remoteDir);
}
// 5. 上传文件
try (FileInputStream fis = new FileInputStream(localFilePath)) {
if (!ftpClient.storeFile(remoteFilePath.substring(remoteFilePath.lastIndexOf('/') + 1), fis)) {
throw new IOException("File upload failed.");
}
System.out.println("File uploaded successfully to: " + remoteFilePath);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 6. 断开连接
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
关键步骤说明
-
连接与登录
- 使用
FTPClient.connect()建立连接,并通过FTPReply.isPositiveCompletion()检查连接状态。 - 登录失败时需抛出异常,避免后续操作无效。
- 使用
-
传输模式设置
setFileType(FTP.BINARY_FILE_TYPE)确保文件以二进制模式传输,避免文本文件换行符或编码问题。
-
目录与文件操作
- 通过
changeWorkingDirectory()切换到目标目录,若目录不存在需提前创建(可通过FTPClient.makeDirectory()实现)。 storeFile()方法执行上传,需捕获IOException处理传输错误。
- 通过
-
资源释放
(图片来源网络,侵删)- 使用
try-with-resources自动关闭FileInputStream,并在finally块中确保FTP连接被正确关闭。
- 使用
常见问题处理
| 问题场景 | 解决方案 |
|---|---|
| 文件上传后大小异常 | 检查传输模式是否为二进制(FTP.BINARY_FILE_TYPE),避免ASCII模式导致的转换问题。 |
| 连接超时 | 在connect()前设置超时时间:ftpClient.setConnectTimeout(5000)(单位:毫秒)。 |
相关问答FAQs
Q1: 如何处理FTP服务器上的中文路径或文件名乱码问题?
A: 可通过设置FTP客户端的字符编码解决,在登录后添加:ftpClient.setControlEncoding("UTF-8"),并确保服务器端支持UTF-8编码,若服务器使用GBK等编码,需将本地字符串转换为对应编码后再传输。
Q2: 如何实现FTP文件上传的进度显示?
A: Commons Net本身不直接支持进度监听,可通过自定义InputStream包装类实现,继承FilterInputStream重写read()方法,在每次读取数据时计算已传输字节数,并通过回调接口通知进度,示例代码片段如下:
public class ProgressInputStream extends FilterInputStream {
private long transferred;
private ProgressMonitor monitor;
public ProgressInputStream(InputStream in, ProgressMonitor monitor) {
super(in);
this.monitor = monitor;
}
@Override
public int read() throws IOException {
int r = super.read();
if (r != -1) transferred++;
monitor.transferred(transferred);
return r;
}
// 其他read()方法需类似重写
}
其中ProgressMonitor为自定义接口,包含transferred(long bytes)方法用于更新进度。
