一.概述

FTP是用来传送文件的协议.使用FTP实现远程文件传输的同时,还可以保证数据传输的可靠性和高效性.
FTP是基于TCP传输的,所以数据在传输的过程中可靠性得到了保障,基于TCP20.21端口.

二.传输过程

image.png
客户端 服务器

image.png

三.搭建FTP服务器

1.导包

  1. <dependency>
  2. <groupId>org.apache.ftpserver</groupId>
  3. <artifactId>ftpserver-core</artifactId>
  4. <version>1.1.1</version>
  5. <scope>compile</scope>
  6. </dependency>

2.代码

  1. package com.example.demo.controller;
  2. import org.apache.ftpserver.FtpServer;
  3. import org.apache.ftpserver.FtpServerFactory;
  4. import org.apache.ftpserver.ftplet.Authority;
  5. import org.apache.ftpserver.ftplet.FtpException;
  6. import org.apache.ftpserver.listener.ListenerFactory;
  7. import org.apache.ftpserver.usermanager.impl.BaseUser;
  8. import org.apache.ftpserver.usermanager.impl.WritePermission;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. /**
  12. * @Author leaves
  13. * @Date 2022/5/6 19:34
  14. */
  15. public class FileUtilController {
  16. public static void main(String[] args) throws FtpException {
  17. FtpServerFactory serverFactory = new FtpServerFactory();
  18. ListenerFactory factory = new ListenerFactory();
  19. //设置监听端口
  20. factory.setPort(2022);
  21. //替换默认监听
  22. serverFactory.addListener("default", factory.createListener());
  23. //用户名
  24. BaseUser user = new BaseUser();
  25. user.setName("yourname");
  26. //密码 如果不设置密码就是匿名用户
  27. user.setPassword("yourpassword");
  28. //用户主目录
  29. user.setHomeDirectory("C:\\images");
  30. List<Authority> authorities = new ArrayList<Authority>();
  31. //增加写权限
  32. authorities.add(new WritePermission());
  33. user.setAuthorities(authorities);
  34. //增加该用户
  35. serverFactory.getUserManager().save(user);
  36. FtpServer server = serverFactory.createServer();
  37. server.start();
  38. }
  39. }

四.连接FTP服务器

1.导包

  1. <dependency>
  2. <groupId>commons-net</groupId>
  3. <artifactId>commons-net</artifactId>
  4. <version>3.5</version>
  5. </dependency>

2.配置工具类

  1. package com.example.demo.ftp;
  2. import org.apache.commons.net.ftp.FTP;
  3. import org.apache.commons.net.ftp.FTPClient;
  4. import org.apache.commons.net.ftp.FTPFile;
  5. import org.apache.commons.net.ftp.FTPReply;
  6. import java.io.*;
  7. import java.net.MalformedURLException;
  8. /**
  9. * @Auther: hrabbit
  10. * @Date: 2018-04-21 下午12:35
  11. * @Description:
  12. */
  13. public class FTPUtils {
  14. public static FTPClient ftpClient = null;
  15. /**
  16. * 初始化ftp服务器
  17. */
  18. public static void initFtpClient(String hostname,String username,String password,Integer port) {
  19. ftpClient = new FTPClient();
  20. /**
  21. * 在上传文件的时候,我们的文件名称有时候需要被保留,但是有时候如果文件名称为中文的话,会产生保存失败的现象,因此只需要将FTPClient的编码方式更改为UTF-8模式即可解决
  22. */
  23. ftpClient.setControlEncoding("UTF-8");
  24. try {
  25. //连接ftp服务器
  26. ftpClient.connect(hostname, port);
  27. //登录ftp服务器
  28. ftpClient.login(username, password);
  29. //是否成功登录服务器
  30. int replyCode = ftpClient.getReplyCode();
  31. if(FTPReply.isPositiveCompletion(replyCode)){
  32. System.out.println("ftp服务器登录成功");
  33. }
  34. }catch (MalformedURLException e) {
  35. e.printStackTrace();
  36. }catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. /**
  41. * 上传文件
  42. * @param pathname ftp服务保存地址
  43. * @param fileName 上传到ftp的文件名
  44. * @param inputStream 输入文件流
  45. * @return
  46. */
  47. public static boolean uploadFile(String hostname,String username,String password,Integer port, String pathname, String fileName,InputStream inputStream){
  48. boolean flag = false;
  49. try{
  50. System.out.println("开始上传文件");
  51. initFtpClient(hostname,username,password,port);
  52. /**
  53. * 二进制形式上传文件
  54. */
  55. ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
  56. /**
  57. * 主动模式和被动模式的不同简单概述为: 主动模式传送数据时是“服务器”连接到“客户端”的端口;被动模式传送数据是“客户端”连接到“服务器”的端口。
  58. 主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
  59. 被动模式只需要服务器端开放端口给客户端连接就行了。
  60. 因此只需要将模式改为被动模式即可:
  61. */
  62. ftpClient.enterLocalPassiveMode();
  63. CreateDirecroty(pathname);
  64. // ftpClient.makeDirectory(pathname);
  65. ftpClient.setControlEncoding("utf-8");
  66. ftpClient.storeFile(fileName, inputStream);
  67. System.out.println("上传结束");
  68. inputStream.close();
  69. ftpClient.logout();
  70. flag = true;
  71. System.out.println("上传文件成功");
  72. }catch (Exception e) {
  73. System.out.println("上传文件失败");
  74. e.printStackTrace();
  75. }finally{
  76. if(ftpClient.isConnected()){
  77. try{
  78. ftpClient.disconnect();
  79. }catch(IOException e){
  80. e.printStackTrace();
  81. }
  82. }
  83. if(null != inputStream){
  84. try {
  85. inputStream.close();
  86. } catch (IOException e) {
  87. e.printStackTrace();
  88. }
  89. }
  90. }
  91. return true;
  92. }
  93. //改变目录路径
  94. public static boolean changeWorkingDirectory(String directory) {
  95. boolean flag = true;
  96. try {
  97. flag = ftpClient.changeWorkingDirectory(directory);
  98. if (flag) {
  99. System.out.println("进入文件夹" + directory + " 成功!");
  100. } else {
  101. System.out.println("进入文件夹" + directory + " 失败!开始创建文件夹");
  102. }
  103. } catch (IOException ioe) {
  104. ioe.printStackTrace();
  105. }
  106. return flag;
  107. }
  108. //创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
  109. public static boolean CreateDirecroty(String remote) throws IOException {
  110. boolean success = true;
  111. String directory = remote + "/";
  112. // 如果远程目录不存在,则递归创建远程服务器目录
  113. if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(new String(directory))) {
  114. int start = 0;
  115. int end = 0;
  116. if (directory.startsWith("/")) {
  117. start = 1;
  118. } else {
  119. start = 0;
  120. }
  121. end = directory.indexOf("/", start);
  122. String path = "";
  123. String paths = "";
  124. while (true) {
  125. String subDirectory = new String(remote.substring(start, end).getBytes("UTF-8"), "iso-8859-1");
  126. path = path + "/" + subDirectory;
  127. if (!existFile(path)) {
  128. if (makeDirectory(subDirectory)) {
  129. changeWorkingDirectory(subDirectory);
  130. } else {
  131. System.out.println("创建目录[" + subDirectory + "]失败");
  132. changeWorkingDirectory(subDirectory);
  133. }
  134. } else {
  135. changeWorkingDirectory(subDirectory);
  136. }
  137. paths = paths + "/" + subDirectory;
  138. start = end + 1;
  139. end = directory.indexOf("/", start);
  140. // 检查所有目录是否创建完毕
  141. if (end <= start) {
  142. break;
  143. }
  144. }
  145. }
  146. return success;
  147. }
  148. //判断ftp服务器文件是否存在
  149. public static boolean existFile(String path) throws IOException {
  150. boolean flag = false;
  151. FTPFile[] ftpFileArr = ftpClient.listFiles(path);
  152. if (ftpFileArr.length > 0) {
  153. flag = true;
  154. }
  155. return flag;
  156. }
  157. //创建目录
  158. public static boolean makeDirectory(String dir) {
  159. boolean flag = true;
  160. try {
  161. flag = ftpClient.makeDirectory(dir);
  162. if (flag) {
  163. System.out.println("创建文件夹" + dir + " 成功!");
  164. } else {
  165. System.out.println("创建文件夹" + dir + " 失败!");
  166. }
  167. } catch (Exception e) {
  168. e.printStackTrace();
  169. }
  170. return flag;
  171. }
  172. /** * 下载文件 *
  173. * @param pathname FTP服务器文件目录 *
  174. * @param filename 文件名称 *
  175. * @param localpath 下载后的文件路径 *
  176. * @return */
  177. public static boolean downloadFile(String hostname,String username,String password,Integer port,String pathname, String filename, String localpath){
  178. boolean flag = false;
  179. OutputStream os=null;
  180. try {
  181. System.out.println("开始下载文件");
  182. initFtpClient(hostname,username,password,port);
  183. //切换FTP目录
  184. ftpClient.changeWorkingDirectory(pathname);
  185. FTPFile[] ftpFiles = ftpClient.listFiles();
  186. for(FTPFile file : ftpFiles){
  187. if(filename.equalsIgnoreCase(file.getName())){
  188. File localFile = new File(localpath + "/" + file.getName());
  189. os = new FileOutputStream(localFile);
  190. ftpClient.retrieveFile(file.getName(), os);
  191. os.close();
  192. }
  193. }
  194. ftpClient.logout();
  195. flag = true;
  196. System.out.println("下载文件成功");
  197. } catch (Exception e) {
  198. System.out.println("下载文件失败");
  199. e.printStackTrace();
  200. } finally{
  201. if(ftpClient.isConnected()){
  202. try{
  203. ftpClient.disconnect();
  204. }catch(IOException e){
  205. e.printStackTrace();
  206. }
  207. }
  208. if(null != os){
  209. try {
  210. os.close();
  211. } catch (IOException e) {
  212. e.printStackTrace();
  213. }
  214. }
  215. }
  216. return flag;
  217. }
  218. /** * 删除文件 *
  219. * @param pathname FTP服务器保存目录 *
  220. * @param filename 要删除的文件名称 *
  221. * @return */
  222. public static boolean deleteFile(String hostname,String username,String password,Integer port,String pathname, String filename){
  223. boolean flag = false;
  224. try {
  225. System.out.println("开始删除文件");
  226. initFtpClient(hostname,username,password,port);
  227. //切换FTP目录
  228. ftpClient.changeWorkingDirectory(pathname);
  229. ftpClient.dele(filename);
  230. ftpClient.logout();
  231. flag = true;
  232. System.out.println("删除文件成功");
  233. } catch (Exception e) {
  234. System.out.println("删除文件失败");
  235. e.printStackTrace();
  236. } finally {
  237. if(ftpClient.isConnected()){
  238. try{
  239. ftpClient.disconnect();
  240. }catch(IOException e){
  241. e.printStackTrace();
  242. }
  243. }
  244. }
  245. return flag;
  246. }
  247. }

3.代码

  1. package com.example.demo;
  2. import com.example.demo.ftp.FTPUtils;
  3. import org.junit.jupiter.api.Test;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.IOException;
  8. /**
  9. * @author zhangyixuan
  10. * @version 2022.4
  11. * @date 2022/5/6 8:51
  12. */
  13. @SpringBootTest
  14. public class FtpTest {
  15. /**
  16. * FTP登录
  17. */
  18. @Test
  19. public void test01(){
  20. FTPUtils.initFtpClient("localhost", "user", "12345", 2022);
  21. }
  22. /**
  23. * 文件上传
  24. * @throws IOException
  25. */
  26. @Test
  27. public void test02() throws IOException {
  28. FTPUtils.uploadFile("localhost", "user", "12345", 2022,"ftp",
  29. "test001.jpg",new FileInputStream("D:\\dog.jpg"));
  30. }
  31. /**
  32. * 文件下载
  33. *
  34. */
  35. @Test
  36. public void test03(){
  37. FTPUtils.downloadFile("localhost", "user", "12345", 2022,"ftp",
  38. "test001.jpg","D:\\Desktop\\ftp");
  39. }
  40. /**
  41. * 删除文件
  42. * @throws IOException
  43. */
  44. @Test
  45. public void test05() {
  46. FTPUtils.deleteFile("localhost", "user", "12345", 2022, "ftp","test001.jpg");
  47. }
  48. /**
  49. * 创建文件夹
  50. */
  51. @Test
  52. public void test06(){
  53. FTPUtils.initFtpClient("localhost", "user", "12345", 2022);
  54. FTPUtils.makeDirectory("/ftp/666");
  55. }
  56. /**
  57. * 文件夹是否存在
  58. * @throws IOException
  59. */
  60. @Test
  61. public void test04() throws IOException {
  62. FTPUtils.initFtpClient("localhost", "user", "12345", 2022);
  63. System.out.println(FTPUtils.existFile("dog.jpg"));
  64. }
  65. }