注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!

温馨提示:(默认权限下,暂不支持往本地的C盘中写入文件)

一、引入依赖

<!-- https://mvnrepository.com/artifact/commons-net/commons-net --><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version></dependency>

二、获取配置信息 FTPConfig

2.1 添加yml配置

system:ftp:# ftp 文件服务器配置信息userName: xxxpassword: xxxhost: xxxport: 21 # 默认

2.2 获取配置

package com.jxz.owner.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @Description: FTP 文件服务器配置** @Date: 2022/2/14* @Author: jiangXueZhi*/
@Data
@Component
@ConfigurationProperties(prefix = "system.ftp")
public class FTPConfig {private String userName;private String password;private String host;private int port;
}

三、程序入口

/*** FTP 的Java客户端操作(暂不支持在本地的C盘中写入文件)*/@RequestMapping(value = "/ftpFileHandle", method = RequestMethod.GET)public void ftpFileHandle() {/* FTP 基操 */
//        FTPClient ftp = FTPUtils.getFTPClient(ftpConfig.getHost(), ftpConfig.getPort(), ftpConfig.getUserName(), ftpConfig.getPassword()); // 获取 ftp客户端
//        FTPUtils.downLoadFTP(ftp, "/report", "测试文件.txt", "D:\\");
//        FTPUtils.copyFile(ftp, "/report", "/report/test", "jxz.txt");
//        FTPUtils.uploadFile(ftp, "D:\\测试文件3.txt", "/report");
//        FTPUtils.moveFile(ftp, "/report/test", "/report/test2");
//        FTPUtils.deleteByFolder(ftp, "/report/test");
//        System.out.println(FTPUtils.readFileByFolder(ftp, "/report/test2"));
//        FTPUtils.closeFTP(ftp);
//        System.exit(0);/* FTP 上传与下载的快捷操作 */
//        FTPUtils.uploadFile("hello shenzhen,你好 深圳", ftpConfig.getUserName(), ftpConfig.getPassword(), ftpConfig.getHost(), ftpConfig.getPort(), "测试文件.txt", "/report");
//        FTPUtils.downLoadFile(ftpConfig.getUserName(), ftpConfig.getPassword(), ftpConfig.getHost(), ftpConfig.getPort(), "测试文件.txt", "/report", "D:\\");}

四、工具类 FTPUtils

package com.paycool.inpay.core.utils;import lombok.Data;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.*;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;/*** @Description: JAVA 操作 FTP 文件服务器的工具类** @Date: 2022/2/14* @Author: jiangXueZhi*/
public class FTPUtils {private static final Logger LOGGER = LoggerFactory.getLogger(FTPUtils.class);/*** 获取FTPClient对象** @param ftpHost     服务器IP* @param ftpPort     服务器端口号* @param ftpUserName 用户名* @param ftpPassword 密码* @return FTPClient*/public static FTPClient getFTPClient(String ftpHost, int ftpPort, String ftpUserName, String ftpPassword) {FTPClient ftp = null;try {ftp = new FTPClient();// 连接FPT服务器,设置IP及端口ftp.connect(ftpHost, ftpPort);// 设置用户名和密码ftp.login(ftpUserName, ftpPassword);// 设置连接超时时间,5000毫秒ftp.setConnectTimeout(5000);// 设置中文编码集,防止中文乱码ftp.setControlEncoding("UTF-8");if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {LOGGER.info("未连接到FTP,用户名或密码错误");ftp.disconnect();} else {LOGGER.info("FTP连接成功");}} catch (SocketException e) {e.printStackTrace();LOGGER.info("FTP的IP地址可能错误,请正确配置");} catch (IOException e) {e.printStackTrace();LOGGER.info("FTP的端口错误,请正确配置");}return ftp;}/*** 关闭FTP** @param ftp ftp客户端* @return 关闭*/public static boolean closeFTP(FTPClient ftp) {try {ftp.logout();} catch (Exception e) {LOGGER.error("FTP关闭失败");} finally {if (ftp.isConnected()) {try {ftp.disconnect();} catch (IOException ioe) {LOGGER.error("FTP关闭失败");}}}return false;}/* ---------------------------- FTP 基操 start ---------------------------- *//*** 下载FTP下指定文件** @param ftp      ftp客户端* @param filePath FTP文件路径* @param fileName 文件名* @param downPath 下载保存的目录* @param deleteLocalFile true:删除本地文件* @return FTP下指定文件*/public static boolean downLoadFTP(FTPClient ftp, String filePath, String fileName, String downPath, boolean deleteLocalFile) {// 默认失败boolean flag = false;try {// 跳转到文件目录ftp.changeWorkingDirectory(filePath);// 获取目录下文件集合ftp.enterLocalPassiveMode();FTPFile[] files = ftp.listFiles();for (FTPFile file : files) {// 取得指定文件并下载if (file.getName().equals(fileName)) {File downFile = new File(downPath + "/" + file.getName());OutputStream out = new FileOutputStream(downFile);// 绑定输出流下载文件,需要设置编码集,不然可能出现文件为空的情况flag = ftp.retrieveFile(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), out);// 下载成功后删除文件if (deleteLocalFile) {ftp.deleteFile(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));}out.flush();out.close();if (flag) {LOGGER.info("下载成功");} else {LOGGER.error("下载失败");}}}} catch (Exception e) {LOGGER.error("下载失败");}return flag;}/*** FTP文件上传** @param ftp      ftp客户端* @param filePath 源文件夹地址* @param ftpPath  目标文件夹地址* @return 上传成功与否*/public static boolean uploadFile(FTPClient ftp, String filePath, String ftpPath) {boolean flag = false;InputStream in = null;try {// 设置PassiveMode传输ftp.enterLocalPassiveMode();// 设置二进制传输,使用BINARY_FILE_TYPE,ASC容易造成文件损坏ftp.setFileType(FTPClient.BINARY_FILE_TYPE);// 判断FPT目标文件夹是否存在 不存在则创建if (!ftp.changeWorkingDirectory(ftpPath)) {ftp.makeDirectory(ftpPath);}// 跳转目标目录ftp.changeWorkingDirectory(ftpPath);// 上传文件File file = new File(filePath);in = new FileInputStream(file);String tempName = ftpPath + "/" + file.getName();flag = ftp.storeFile(new String(tempName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), in);if (flag) {LOGGER.info("上传成功");} else {LOGGER.error("上传失败");}} catch (Exception e) {e.printStackTrace();LOGGER.error("上传失败");} finally {try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}}return flag;}/*** FPT上文件的复制** @param ftp      ftp客户端* @param olePath  原文件地址* @param newPath  新保存地址* @param fileName 文件名* @return 复制成功与否*/public static boolean copyFile(FTPClient ftp, String olePath, String newPath, String fileName) {boolean flag = false;try {// 跳转到文件目录ftp.changeWorkingDirectory(olePath);// 设置连接模式,不设置会获取为空ftp.enterLocalPassiveMode();// 获取目录下文件集合FTPFile[] files = ftp.listFiles();ByteArrayInputStream in;ByteArrayOutputStream out;for (FTPFile file : files) {// 取得指定文件并下载if (file.getName().equals(fileName)) {// 读取文件,使用下载文件的方法把文件写入内存,绑定到out流上out = new ByteArrayOutputStream();ftp.retrieveFile(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), out);in = new ByteArrayInputStream(out.toByteArray());// 创建新目录ftp.makeDirectory(newPath);// 文件复制,先读,再写// 二进制ftp.setFileType(FTPClient.BINARY_FILE_TYPE);flag = ftp.storeFile(newPath + "/" + (new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)), in);out.flush();out.close();in.close();if (flag) {LOGGER.info("转存成功");} else {LOGGER.error("复制失败");}}}} catch (Exception e) {LOGGER.error("复制失败");}return flag;}/*** 实现文件夹的移动,这里做的是一个文件夹下的所有内容移动到新的文件,* 如果要做指定文件移动,加个判断判断文件名* 如果不需要移动,只是需要文件重命名,可以使用ftp.rename(oleName,newName)** @param ftp     ftp 客户端* @param oldPath 文件源地址* @param newPath 文件目标地址* @return 移动成功与否*/public static boolean moveDirectory(FTPClient ftp, String oldPath, String newPath) {boolean flag = false;try {ftp.changeWorkingDirectory(oldPath);ftp.enterLocalPassiveMode();// 获取文件数组FTPFile[] files = ftp.listFiles();// 新文件夹不存在则创建if (!ftp.changeWorkingDirectory(newPath)) {ftp.makeDirectory(newPath);}//回到原有工作目录ftp.changeWorkingDirectory(oldPath);for (FTPFile file : files) {// 转存目录flag = ftp.rename(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1),newPath + "/" + new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));if (flag) {LOGGER.info(file.getName() + "移动成功");} else {LOGGER.error(file.getName() + "移动失败");}}} catch (Exception e) {e.printStackTrace();LOGGER.error("移动文件失败");}return flag;}/*** 移动文件** @param ftp xx* @param oldPath xx* @param newPath xx* @return xx*/public static boolean moveFile(FTPClient ftp, String oldPath, String newPath) {boolean flag = false;try {ftp.changeWorkingDirectory(oldPath);ftp.enterLocalPassiveMode();// 获取文件数组FTPFile[] files = ftp.listFiles();// 新文件夹不存在则创建if (!ftp.changeWorkingDirectory(newPath)) {ftp.makeDirectory(newPath);}//回到原有工作目录ftp.changeWorkingDirectory(oldPath);for (FTPFile file : files) {if (file.isFile()) {// 转存目录flag = ftp.rename(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1),newPath + "/" + new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));if (flag) {LOGGER.info(file.getName() + "移动成功");} else {LOGGER.error(file.getName() + "移动失败");}}}} catch (Exception e) {e.printStackTrace();LOGGER.error("移动文件失败");}return flag;}/*** 删除FTP上指定文件夹下文件及其子文件方法,添加了对中文目录的支持** @param ftp       ftp 客户端* @param ftpFolder 需要删除的文件夹* @return 删除成功与否*/public static boolean deleteByFolder(FTPClient ftp, String ftpFolder) {boolean flag = false;try {ftp.changeWorkingDirectory(new String(ftpFolder.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));ftp.enterLocalPassiveMode();FTPFile[] files = ftp.listFiles();for (FTPFile file : files) {// 判断为文件则删除if (file.isFile()) {ftp.deleteFile(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));}// 判断是文件夹if (file.isDirectory()) {String childPath = ftpFolder + "/" + file.getName();// 递归删除子文件夹deleteByFolder(ftp, childPath);}}// 循环完成后删除文件夹flag = ftp.removeDirectory(new String(ftpFolder.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));if (flag) {LOGGER.info(ftpFolder + "文件夹删除成功");} else {LOGGER.error(ftpFolder + "文件夹删除成功");}} catch (Exception e) {e.printStackTrace();LOGGER.error("删除失败");}return flag;}/*** 遍历解析文件夹下所有文件** @param folderPath 需要解析的的文件夹* @param ftp        ftp客户端* @return 遍历文件的内容*/public static List<Map<String, Object>> readFileByFolder(FTPClient ftp, String folderPath) {try {ftp.changeWorkingDirectory(new String(folderPath.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));// 设置FTP连接模式ftp.enterLocalPassiveMode();// 获取指定目录下文件文件对象集合FTPFile[] files = ftp.listFiles();InputStream in;BufferedReader reader;List<Map<String, Object>> fileContentList = new LinkedList<>(); // 文件内容集合for (FTPFile file : files) {// 判断为txt文件则解析if (file.isFile()) {String fileName = file.getName();if (fileName.endsWith(".txt")) {in = ftp.retrieveFileStream(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));String temp;StringBuilder buffer = new StringBuilder();while ((temp = reader.readLine()) != null) {buffer.append(temp);}reader.close();in.close();// ftp.retrieveFileStream使用了流,需要释放一下,不然会返回空指针ftp.completePendingCommand();// 这里就把一个txt文件完整解析成了个字符串,就可以调用实际需要操作的方法Map<String, Object> map = new HashMap<>();map.put("fileName", fileName);map.put("fileContent", buffer.toString());fileContentList.add(map);}}// 判断为文件夹,递归if (file.isDirectory()) {String path = folderPath + "/" + file.getName();readFileByFolder(ftp, path);}}return fileContentList;} catch (Exception e) {e.printStackTrace();LOGGER.error("文件解析失败");}return null;}/*** 获取文件夹下的单个文件** @param ftp ftp客户端* @param folderPath 需要解析的的文件夹,其中有且仅有一个文件* @param destination 文件写入的本地地址* @return 流 + fileName*/public static File readSingleFileByFolder(FTPClient ftp, String folderPath, String destination) {InputStream in = null;String fileName = null;try {ftp.changeWorkingDirectory(new String(folderPath.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));// 设置FTP连接模式ftp.enterLocalPassiveMode();// 获取指定目录下文件文件对象集合FTPFile[] files = ftp.listFiles();for (FTPFile file : files) {// 判断为文件则解析if (file.isFile()) {in = ftp.retrieveFileStream(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));fileName = file.getName();// ftp.retrieveFileStream使用了流,需要释放一下,不然会返回空指针ftp.completePendingCommand();break; // 目录中有且仅有一个文件}}if (in != null) {return FileUtils.getFile(destination + fileName, in);}} catch (Exception e) {e.printStackTrace();LOGGER.error("文件解析失败");} finally {try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}}return null;}@Datapublic static class ReadSingleFileResult{private InputStream inputStream;private String fileName;}/* ---------------------------- FTP 基操 end ----------------------------*//* ---------------------------- FTP 上传与下载的快捷操作 start ----------------------------*//*** 向ftp写文件(数据)** @param fileContent 要写入的文件内容* @param userName    ftp登录用户名* @param password    ftp登录密码* @param host        ftp的IP地址* @param port        ftp端口号* @param fileName    创建的文件* @param ftpPath     指定写入FTP的目录*/public static void uploadFile(String fileContent, String userName, String password, String host, int port, String fileName, String ftpPath) {FTPClient ftpClient = new FTPClient();try {InputStream in;// 1.输入流in = new ByteArrayInputStream(fileContent.getBytes());// 2.连接服务器ftpClient.connect(host, port);// 3.登录ftpftpClient.login(userName, password);// 4.指定写入Ftp的目录ftpClient.changeWorkingDirectory(ftpPath);// 5.写操作ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);ftpClient.storeFile(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), in);in.close();LOGGER.info("已上传");} catch (Exception e) {e.printStackTrace();} finally {if (ftpClient.isConnected()) {try {ftpClient.disconnect();} catch (Exception e) {e.printStackTrace();}}}}/*** ftp下载数据** @param userName     ftp登录用户名* @param userPassword ftp登录密码* @param host         ftp的IP地址* @param port         ftp的端口号* @param fileName     创建的文件* @param ftpPath      指定FTP的目录* @param localPath    指定本地写入文件的地址*/public static void downLoadFile(String userName, String userPassword, String host, int port, String fileName, String ftpPath, String localPath) {FTPClient ftp = new FTPClient();try {int reply;//1.连接服务器ftp.connect(host, port);//2.登录服务器 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器ftp.login(userName, userPassword);//3.判断登陆是否成功reply = ftp.getReplyCode();if (!FTPReply.isPositiveCompletion(reply)) {LOGGER.info("未连接到FTP,用户名或密码错误");ftp.disconnect();} else {LOGGER.info("FTP连接成功");}//4.指定要下载的目录ftp.changeWorkingDirectory(ftpPath); // 转移到FTP服务器目录//5.遍历下载的目录FTPFile[] fs = ftp.listFiles();for (FTPFile ff : fs) {//解决中文乱码问题,两次解码byte[] bytes = ff.getName().getBytes(StandardCharsets.ISO_8859_1);String fn = new String(bytes, StandardCharsets.UTF_8);if (fn.equals(fileName)) {//6.写操作,将其写入到本地文件中File localFile = new File(localPath + ff.getName());OutputStream is = new FileOutputStream(localFile);ftp.retrieveFile(ff.getName(), is);is.close();}}ftp.logout();LOGGER.info("已下载");} catch (IOException e) {e.printStackTrace();} finally {if (ftp.isConnected()) {try {ftp.disconnect();} catch (IOException e) {e.printStackTrace();}}}}/* ---------------------------- FTP 上传与下载的快捷操作 end ----------------------------*/
}

五、下载 FTP 客户端 FileZilla 进行测试

5.1 下载地址:

FileZilla - The free FTP solution

5.2  下载安装步骤:

A.  B. 

C.  D. 安装无脑下一步,注意创建桌面 icon 即可

5.3 界面说明

FTP 的Java客户端操作相关推荐

  1. Redis介绍 Java客户端操作Redis

    Redis介绍 && Java客户端操作Redis 本文内容 redis介绍 redis的 shell 客户端简介 redis的 java 客户端简介 环境配置 redis 2.8.1 ...

  2. Redis介绍 Java客户端操作Redis

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow Redis介绍 & ...

  3. 【Java从0到架构师】Zookeeper 应用 - Java 客户端操作、服务器动态感知、分布式锁业务处理

    分布式基石 Zookeeper 框架全面剖析 Java 客户端操作 Java 客户端 API 服务器的动态感知 服务注册 服务发现 分布式锁业务处理 单机环境(一个虚拟机中) 分布式环境_同名节点 分 ...

  4. Redis java客户端操作

    jedis jedis官方指定的redis java客户端,将其导入到pom.xml问价内 <!-- https://mvnrepository.com/artifact/redis.clien ...

  5. idea zookeeper插件使用_zookeeper的Java客户端操作

    客户端选择 zookeeper的Java客户端主要有zkclient和Curator,此篇文章介绍Curator,就冲他官网的简介,zookeeper书的作者Patrick Hunt给了这么高的评价: ...

  6. java客户端操作elasticsearch7.3.2版本

    前面一篇介绍了使用kibana操作elasticsearch,使用的版本都是最新版7.3.2,现在我们开始使用java客户端来操作elasticsearch. 一.索引管理 1.1 搭建工程 1.1. ...

  7. java day47【redis概念 、下载安装 、 命令操作 、持久化操作 、使用Java客户端操作redis】...

    第一章  Redis 1. 概念: redis是一款高性能的NOSQL系列的非关系型数据库 1.1.什么是NOSQL NoSQL(NoSQL = Not Only SQL),意即"不仅仅是S ...

  8. 【Redis】Java客户端操作reids数据库

    目录 一.Java客户端分类 1.Jedis 2.lettuce 3.Redisson 二.Jedis 三.reids连接池 一.Java客户端分类 Redis提供了多个版本的Java客户端,其中推荐 ...

  9. 使用Java客户端操作elasticsearch

    常见的配置 前面已介绍过,RestClientBuilder支持同时提供一个RequestConfigCallback和一个HttpClientConfigCallback,你可以定制 the Apa ...

最新文章

  1. 大型网站技术架构文摘
  2. centos配置oracle自启,centos 下配置oracle11gR2开机自启
  3. (模板)网页游戏用的“内容区”的“图赏影音”模板
  4. linux fg 命令,Linux fg 命令 command not found fg 命令详解 fg 命令未找到 fg 命令安装 - CommandNotFound ⚡️ 坑否...
  5. 谈谈我这几年的C++学习之路
  6. iOS 13.2正式版放出 支持AirPodsPro
  7. python测验4_Python小测试_4
  8. oracle 数据库er生成,oracle数据库生成er图
  9. 使用最新的跨平台框架Electron 实现 STM32 MCU 嵌入式系统的序列号烧写器上位机开发
  10. 定义一个基类BAse,有两个公有成员函数fn1,fn2;私有派生出derived类,如何通过derived类的对象调用基类的函数fn1;
  11. Failed to fetch URl https://dl-ssl.google.com/android/repository/addo Android SDK更新以及ADT更新出现问题的解决办法
  12. MT4开发 之开发自己的数据源系统(dde UniversalDDEConnector )
  13. java 引入微信sdk_手把手教您开发JAVA微信SDK-新手接入
  14. UE5 Live Coding编译出错时乱码问题解决方法
  15. 计算机上平方米的单位,word怎么写平方米 word中平方米的单位怎么打
  16. Hive学习(待续)
  17. [日常训练] 联络网
  18. 努力是为了让自己不平庸
  19. 5G/NR 随机接入过程之PRACH时域资源
  20. 信捷plc的pid控制_基于信捷plc的pid参数自整定的温度控制

热门文章

  1. 宣传一下一个在线SEO工具:http://www.linjunseo.com/seo
  2. (惊爆)网络营销公司/网络营销课程:关于如何做网络营销推广和流量的秘密
  3. 百度网盘妥协了 简单设置即可提速好几倍的p2p上传技术 无需插件破解
  4. 安卓手机管理软件_vaa云录音app下载-vaa云录音手机版下载v1.1.9 安卓版
  5. 财付通 商户证书pfx转pem(转)
  6. 2020 DASCTF四月春季战-misc
  7. 金蝶K3 SQL报表系列-供应商科目余额表
  8. 艾美捷抗人IL-5单抗5A10相关参数说明
  9. buck电路 dac stm32_基于STM32F334双向同步整流BUCK-BOOST数字电源设计
  10. 用JavaScript制作页面特效