pom依赖
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
FTP配置类
// lombok 注解
@Data
public class FtpConfigDto {
private String ip;
private int port;
private String user;
private String password;
private String charset;
private int connectTimeout;
private int dataTimeout;
private int keepAliveTimeout;
private FTPClient ftpClient;
}
FTP文件上传数据
// lombok 注解
@Data
@AllArgsConstructor
public class FtpFileEntry {
private String path;
private File file;
}
FTP工具类
// lombok 注解
@Slf4j
public class FtpUtil {
public static final String SPLITTER = "/";
public static final int BUFFER_SIZE = 1024; public static final int INTQUANTUM_SECOND_MILLIS = 1000;
public static void upload(FtpConfigDto config, String path, File file) {
List<FtpFileEntry> list = new ArrayList<>();
list.add(new FtpFileEntry(path, file));
upload(config, list);
}
public static void upload(FtpConfigDto config, String path, MultipartFile multipartFile) {
try {
String fileName = multipartFile.getOriginalFilename();
String prefix = fileName.substring(fileName.lastIndexOf("."));
File file = File.createTempFile(fileName, prefix);
multipartFile.transferTo(file);
upload(config, path, new FileInputStream(file));
} catch (IOException e) {
log.info("文件上传错误 " + config.getIp(), e);
throw new RuntimeException("文件上传错误 " + config.getIp(), e);
}
}
public static void upload(FtpConfigDto config, String path, InputStream inputStream) {
try {
connect(config);
String dir = getDir(path);
String fileName = getFileName(path);
changeWorkDir(config.getFtpClient(), dir);
boolean isSuccess = config.getFtpClient().storeFile(convertFileName(fileName), inputStream);
if(!isSuccess){
throw new RuntimeExcepton("创建FTP文件失败 ");
}
} catch (IOException e) {
log.info("文件上传错误 " + config.getIp(), e);
throw new RuntimeException("文件上传错误 " + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
}
public static void upload(FtpConfigDto config, List<FtpFileEntry> list) {
validateLocalFile(list);
try {
connect(config);
for (FtpFileEntry entry : list) {
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(entry.getFile()))) {
String dir = getDir(entry.getPath());
String fileName = getFileName(entry.getPath());
changeWorkDir(config.getFtpClient(), dir);
boolean isSuccess = config.getFtpClient().storeFile(convertFileName(fileName), inputStream);
if(!isSuccess){
throw new RuntimeExcepton("创建FTP文件失败 ");
}
}
}
} catch (IOException e) {
log.info("文件上传错误 " + config.getIp(), e);
throw new RuntimeExcepton("文件上传错误 " + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
}
public static InputStream readForFTP(FtpConfigDto config, String path) {
InputStream in;
InputStream returnIn = null;
try {
connect(config);
String dir = getDir(path);
String fileName = getFileName(path);
changeWorkDir(config.getFtpClient(), dir);
validateRemoteFileExist(config.getFtpClient(), dir, fileName);
config.getFtpClient().enterLocalPassiveMode();
in = config.getFtpClient().retrieveFileStream(convertFileName(path));
if (in != null) {
returnIn = cloneInputStream(in);
in.close();
config.getFtpClient().completePendingCommand();
}
} catch (IOException e) {
log.info("FTP服务器文件读取错误 " + config.getIp(), e);
throw new RuntimeExcepton("FTP服务器文件读取错误 " + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
return returnIn;
}
public static void download(FtpConfigDto config, String path, File file) {
List<FtpFileEntry> list = new ArrayList<>();
list.add(new FtpFileEntry(path, file));
download(config, list);
}
public static void download(FtpConfigDto config, List<FtpFileEntry> list) {
try {
connect(config);
for (FtpFileEntry entry : list) {
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(entry.getFile()))) {
String dir = getDir(entry.getPath());
String fileName = getFileName(entry.getPath());
validateRemoteFileExist(config.getFtpClient(), dir, fileName);
boolean isSuccess =
config.getFtpClient().retrieveFile(convertFileName(entry.getPath()), outputStream);
if(!isSuccess){
throw new RuntimeException("FTP下载文件失败");
}
outputStream.flush();
}
}
} catch (IOException e) {
log.info("文件下载错误 " + config.getIp(), e);
throw new RuntimeException("文件下载错误 " + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
}
public static void remove(FtpConfigDto config, String path) {
List<String> list = new ArrayList<>();
list.add(path);
remove(config, list);
}
public static void remove(FtpConfigDto config, List<String> list) {
try {
connect(config);
for (String path : list) {
String dir = getDir(path);
String fileName = getFileName(path);
validateRemoteFileExist(config.getFtpClient(), dir, fileName);
boolean isSuccess = config.getFtpClient().deleteFile(convertFileName(path));
if (!isSuccess) {
throw new RuntimeException("FTP文件删除失败");
}
}
} catch (IOException e) {
log.info("文件删除错误 " + config.getIp(), e);
throw new RuntimeException("文件删除错误 " + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
}
public static void move(FtpConfigDto config, String oldFilePath, String newFilePath) {
try {
connect(config);
validateRemoteFileExist(config.getFtpClient(), getDir(oldFilePath), getFileName(oldFilePath));
boolean isSuccess = config.getFtpClient().rename(oldFilePath, newFilePath);
if (!isSuccess) {
throw new RuntimeException("FTP文件移动失败");
}
} catch (IOException e) {
log.info("文件移动错误" + config.getIp(), e);
throw new RuntimeException("文件移动错误" + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
}
public static void rename(FtpConfigDto config, String path, String oldName, String newName) {
try {
connect(config);
validateRemoteFileExist(config.getFtpClient(), path, oldName);
changeWorkDir(config.getFtpClient(), path);
boolean isSuccess = rename(config.getFtpClient(), oldName, newName);
if (!isSuccess) {
throw new RuntimeException("FTP文件重命名失败");
}
} catch (IOException e) {
log.info("文件重命名错误" + config.getIp(), e);
throw new RuntimeException("文件重命名错误" + config.getIp(), e);
} finally {
disConnect(config.getFtpClient());
}
}
private static boolean rename(FTPClient ftpClient, String oldName, String newName) throws IOException {
return ftpClient.rename(oldName, newName);
}
private static void connect(FtpConfigDto config) throws IOException {
FTPClient ftpClient = new FTPClient();
config.setFtpClient(ftpClient);
ftpClient.connect(config.getIp(), config.getPort());
if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
boolean isLogin = ftpClient.login(config.getUser(), config.getPassword());
if(!isLogin){
throw new RuntimeException("FTP登陆失败");
}
ftpClient.setControlEncoding(config.getCharset());
if (StandardCharsets.UTF_8.name().equals(config.getCharset())
&& FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {
ftpClient.setControlEncoding(StandardCharsets.UTF_8.name());
}
setConfig(config);
}
}
private static void setConfig(FtpConfigDto config) throws IOException {
FTPClient ftpClient = config.getFtpClient();
ftpClient.setBufferSize(BUFFER_SIZE);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
ftpClient.setConnectTimeout(config.getConnectTimeout() * INTQUANTUM_SECOND_MILLIS);
ftpClient.setDataTimeout(config.getDataTimeout() * INTQUANTUM_SECOND_MILLIS);
ftpClient.setControlKeepAliveTimeout(config.getKeepAliveTimeout() * INTQUANTUM_SECOND_MILLIS);
// 设置被动模式
ftpClient.enterLocalPassiveMode();
}
private static void disConnect(FTPClient ftpClient) {
try {
if (ftpClient != null && ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
log.info("关闭FTP连接错误", e);
}
}
private static void changeWorkDirDirect(FTPClient ftpClient, String path) throws IOException {
boolean isSuccess = ftpClient.changeWorkingDirectory(path);
if(!isSuccess){
throw new RuntimeException("工作区跳转失败");
}
}
private static void changeWorkDir(FTPClient ftpClient, String dir) throws IOException {
if (ftpClient.changeWorkingDirectory(dir)) {
return;
}
StringBuilder pathTemp = new StringBuilder();
for (String token : StrUtil.split(dir, SPLITTER)) {
pathTemp.append(SPLITTER).append(token);
if (!ftpClient.changeWorkingDirectory(pathTemp.toString())) {
log.debug("目录名称为:" + token);
boolean isSuccess = ftpClient.makeDirectory(token);
if (!isSuccess){
throw new RuntimeException("创建FTP目录失败");
}
changeWorkDirDirect(ftpClient, pathTemp.toString());
}
}
}
private static void validateLocalFile(List<FtpFileEntry> list) {
if(CollectionUtils.isEmpty(list)){
throw new RuntimeException("FTP本地文件列表为空");
}
for (FtpFileEntry ftpUploadEntry : list) {
FileValidate.validateExist(ftpUploadEntry.getFile());
}
}
private static void validateRemoteFileExist(FTPClient ftpClient, String dir, String fileName) throws IOException {
if (!isRemoteFileExist(ftpClient, dir, fileName)) {
throw new RuntimeException("远程文件不存在");
}
}
private static boolean isRemoteFileExist(FTPClient ftpClient, String dir, String fileName) throws IOException {
FTPFile[] arr = ftpClient.listFiles(dir, new FTPFileFilter() {
@Override
public boolean accept(FTPFile ftpFile) {
return ftpFile.getName().equals(fileName);
}
});
return ArrayUtils.isNotEmpty(arr);
}
public static String getDir(String path) {
int i = path.lastIndexOf(SPLITTER);
return path.substring(0, i);
}
private static String getFileName(String path) {
int i = path.lastIndexOf(SPLITTER);
return path.substring(i + 1);
}
private static String convertFileName(String fileName) {
return new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
}
private static InputStream cloneInputStream(InputStream input) throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
InputStream inputStream;
byte[] buffer = new byte[BUFFER_SIZE];
int len;
while ((len = input.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
inputStream = new ByteArrayInputStream(baos.toByteArray());
return inputStream;
} catch (IOException e) {
log.info("复制inputStream失败", e);
throw e;
}
}
}