使用 JAVA 代码对 FTP 进行上传、下载文件操作 方式一:
- 增加依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
- 代码
package com.wheelmouse.ftp.service.impl;
import com.jcraft.jsch.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* 同名文件上传是覆盖操作。
* 文件路径是不存在则创建,存在直接就可以上传。
*
* @author wheelmouse
* @date 2024/11/22
* @apiNote
*/
@Component
public class SftpServiceImpl {
@Value("${sftp.host}")
private String host;
@Value("${sftp.port}")
private int port;
@Value("${sftp.username}")
private String username;
@Value("${sftp.password}")
private String password;
public Session connect() throws JSchException {
JSch jsch = new JSch();
Session session = jsch.getSession(username, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
return session;
}
private void disconnect(ChannelSftp channel, Session session) {
if (channel != null) {
channel.exit();
}
if (session != null) {
session.disconnect();
}
}
/**
* @param localFilePath 源文件路径+文件名
* @param remoteFilePath 上传到sftp之后的文件名称
* @param filePath 上传到sftp的路径
*/
public void upload(String localFilePath, String remoteFilePath, String filePath) {
Session session = null;
ChannelSftp channel = null;
try {
//创建SFTP连接
session = connect();
//创建SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
//判断目标文件夹是否存在,如果不存在则创建
try {
SftpATTRS attrs = channel.lstat(filePath);
if (attrs == null || !attrs.isDir()) {
createDirectories(channel, filePath);
}
} catch (SftpException f) {
if (f.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
//channel.mkdir(filePath);
createDirectories(channel, filePath);
}
}
channel.cd(filePath);
//上传文件
channel.put(localFilePath, remoteFilePath);
} catch (JSchException | SftpException e) {
e.printStackTrace();
} finally {
//关闭通道和会话
disconnect(channel, session);
}
}
/**
* 递归创建文件夹
* @param channel
* @param path
* @throws SftpException
*/
private void createDirectories(ChannelSftp channel, String path) throws SftpException {
String[] parts = path.split("/");
StringBuilder currentPath = new StringBuilder();
for (String part : parts) {
if (part.isEmpty()) {
// 跳过空部分
continue;
}
currentPath.append("/").append(part);
try {
SftpATTRS attrs = channel.lstat(currentPath.toString());
if (attrs == null || !attrs.isDir()) {
channel.mkdir(currentPath.toString());
}
} catch (SftpException e) {
if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
channel.mkdir(currentPath.toString());
}
}
}
}
public List<String> listFiles(String directory) {
Session session = null;
ChannelSftp channel = null;
try {
//创建SFTP连接
session = connect();
//创建SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
//获取目录列表
Vector<ChannelSftp.LsEntry> list = channel.ls(directory);
List<String> fileNameList = new ArrayList<>();
for (ChannelSftp.LsEntry lsEntry : list) {
String fileName = lsEntry.getFilename();
if (!fileName.equals(".") && !fileName.equals("..") && fileName.endsWith(".json")) {
fileNameList.add(fileName);
}
}
return fileNameList;
} catch (JSchException | SftpException e) {
e.printStackTrace();
} finally {
//关闭通道和会话
disconnect(channel, session);
}
return null;
}
/**
* 下载文件
* @param directory 目标文件所在目录
* @param fileName 文件名
* @param localDirectory 本地目录
* @return
*/
public File downloadFile(String directory, String fileName, String localDirectory) {
Session session = null;
ChannelSftp channel = null;
File localFile = null;
try {
// 创建SFTP连接
session = connect();
// 创建SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
// 构建本地文件路径
File localDir = new File(localDirectory);
if (!localDir.exists()) {
localDir.mkdirs();
}
localFile = new File(localDir, fileName);
// 下载文件到本地
FileOutputStream fos = new FileOutputStream(localFile);
channel.get(directory + "/" + fileName, fos);
fos.close();
return localFile;
} catch (JSchException | SftpException | IOException e) {
e.printStackTrace();
} finally {
// 关闭通道和会话
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
return null;
}
public InputStream get(String directory, String fileName) {
Session session = null;
ChannelSftp channel = null;
try {
//创建SFTP连接
session = connect();
//创建SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
return channel.get(directory + "/" + fileName);
} catch (JSchException | SftpException e) {
e.printStackTrace();
} finally {
//关闭通道和会话
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
return null;
}
}
方式二:
- 增加依赖
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
- 代码
package com.wheelmouse.ftp.service.commons.utils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @Description ftp工具类
* @date 2018-03-22
*/
@Component
@Configuration
public class FtpUtil {
// ftp服务器ip地址
@Value("${spring.ftp.ip}")
private String FTP_ADDRESS;
// 端口号
@Value("${spring.ftp.port}")
private int FTP_PORT;
// 用户名
@Value("${spring.ftp.username}")
private String FTP_USERNAME;
// 密码
@Value("${spring.ftp.password}")
private String FTP_PASSWORD;
public boolean uploadFile(String remoteDirectory, String remoteFileName, InputStream input) {
boolean success = false;
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF-8");
try {
int reply;
ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器
ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return success;
}
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
// 切换到指定目录
ftp.makeDirectory(remoteDirectory);
// 切换为本地被动模式,可以解决FTP上传后文件为空的问题,但需要服务器将FTP服务添加至防火墙白名单
ftp.enterLocalPassiveMode();
// // 切换到指定目录
ftp.changeWorkingDirectory(remoteDirectory);
ftp.storeFile(remoteFileName, input);
input.close();
ftp.logout();
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return success;
}
}