简单的FTP文件目录操作
简单记录一下测试FTP上传文件以及循环建立目录的操作方法,包含原生FTPClient操作以及hutoo工具类的操作。
package cn.git.foreign;
import cn.hutool.extra.ftp.Ftp;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
/**
* FTP文件上传简单案例
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2022-05-24
*/
public class FarmingTest {
public static void main(String[] args) throws ParseException, IOException {
testFtpMkdir();
testHutooFtpMkdir();
}
/**
* 测试hutool ftp上传
*/
private static void testHutooFtpMkdir() throws IOException {
// hutoo工具类上传
Ftp ftp = new Ftp("3.1.19.54", 21, "esbagent", "EsbAgent@2024#CCMS");
ftp.mkDirs("/CUS/RISK/FTP_TEST/2025-06-06");
// 改变工作目录
ftp.cd("/CUS/RISK/FTP_TEST/2025-06-06");
// 改变工作目录后上传到 ./ (当前目录即可),否则填写完整目录信息
boolean upload = ftp.upload("./", new File("D:\\test\\jj3.xx"));
if (upload) {
System.out.println("上传成功");
} else {
System.out.println("上传失败");
}
ftp.close();
}
/**
* 原生资源测试ftp上传
*/
private static void testFtpMkdir() {
// 创建FTPClient对象
FTPClient ftpClient = new FTPClient();
FileInputStream fis = null;
try {
// 连接服务器
ftpClient.connect("3.1.19.54", 21);
// 登录认证
boolean loginState = ftpClient.login("esbagent", "EsbAgent@2024#CCMS");
if (!loginState) {
throw new IOException("登录失败");
}
// 被动模式
ftpClient.enterLocalPassiveMode();
// 二进制传输
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// 创建目录逻辑
String basePath = "/CUS/LOAN/FTP_TEST";
String newDir = "/2025-06-06";
// 切换到基础目录(不存在则创建)
if (!ftpClient.changeWorkingDirectory(basePath)) {
createDirectories(ftpClient, basePath.concat(newDir));
// 变更工作目录
ftpClient.changeWorkingDirectory(basePath);
}
// 文件上传
File localFile = new File("D:\\test\\jj3.xx");
fis = new FileInputStream(localFile);
String remoteFile = localFile.getName();
boolean uploadSuccess = ftpClient.storeFile(remoteFile, fis);
if (uploadSuccess) {
System.out.println("上传成功!");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭连接
if (fis != null) fis.close();
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
/**
* 创建多层级目录逻辑
*
* @param ftpClient
* @param path
* @return
* @throws IOException
*/
public static boolean createDirectories(FTPClient ftpClient, String path) throws IOException {
String[] dirs = path.split("/");
for (String dir : dirs) {
if (dir.isEmpty()) continue;
// 尝试进入目录(存在则跳过创建)
if (!ftpClient.changeWorkingDirectory(dir)) {
if (ftpClient.makeDirectory(dir)) {
// 进入新创建的目录
ftpClient.changeWorkingDirectory(dir);
} else {
// 创建失败
return false;
}
}
}
return true;
}
}
最终上传之后服务器内容如下:
浏览器下载文件简单案例
/**
* 下载贷款明细模板文件
*
* @param httpServletResponse
* @throws IOException
*/
public void downloadIdVerificationTempFile(HttpServletResponse httpServletResponse) throws IOException {
// 设置默认用户名密码
String ftpUsername = FTP_SERVER_USERNAME;
String ftpPassword = FTP_SERVER_PASSWORD;
// 获取服务地址信息
String ftpServerIp;
if (PROFILE_SIT.equals(profile)) {
ftpServerIp = FTP_SERVER_IP_SIT;
} else if (PROFILE_SIT_2.equals(profile)) {
ftpServerIp = FTP_SERVER_IP_SIT2;
} else if (PROFILE_UAT.equals(profile)) {
ftpServerIp = FTP_SERVER_IP_UAT;
} else if (PROFILE_UAT2.equals(profile)) {
ftpServerIp = FTP_SERVER_IP_UAT2;
} else if (PROFILE_TEST.equals(profile)) {
ftpServerIp = FTP_SERVER_IP_TEST;
} else if (PROFILE_PROD.equals(profile) || PROFILE_TC.equals(profile)) {
ftpServerIp = prodFtpIp;
ftpUsername = prodFtpUserName;
ftpPassword = prodFtpPassword;
} else {
ftpServerIp = FTP_SERVER_IP_TEST;
}
// 校验文件是否存在
Ftp ftp = new Ftp(ftpServerIp, FTP_SERVER_PORT, ftpUsername, ftpPassword);
String fileFullPath = DOWNLOAD_PATH.concat("/cxmx_head/贷款清单表头.xlsx");
log.info("获取下载模板文件全路径为:[{}]", fileFullPath);
boolean ifExistRemoteFile = ftp.existFile(fileFullPath);
if (!ifExistRemoteFile) {
throw new ServiceException("下载模板文件不存在,请确认");
}
// 下载模板文件
File tempFile = File.createTempFile("temp", ".xlsx");
ftp.download(fileFullPath, tempFile);
// 新增:将文件内容写入HTTP响应流
try (FileInputStream fis = new FileInputStream(tempFile);
ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream()) {
// 使用RFC 5987标准设置文件名,解决乱码问题
String fileName = "贷款清单表头.xlsx";
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
.replaceAll("\\+", "%20");
httpServletResponse.setHeader("Content-Disposition",
"attachment; filename*=UTF-8''" + encodedFileName);
httpServletResponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
httpServletResponse.setCharacterEncoding(StandardCharsets.UTF_8.name());
httpServletResponse.setContentLengthLong(tempFile.length());
// 将文件内容写入输出流
byte[] buffer = new byte[1024 * 8];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
servletOutputStream.write(buffer, 0, bytesRead);
}
servletOutputStream.flush();
} catch (Exception e) {
log.error("下载模板文件失败", e);
throw new ServiceException("文件下载失败: " + e.getMessage());
} finally {
if (tempFile.exists()) {
tempFile.delete();
}
}
}