JAVA 实现 FTP 文件上传、下载和删除

2022-09-13 17:44:40 浏览数 (1)

一、背景

项目中可能经常会遇到需要文件上传到服务器上,需要的时候从服务器获取。结合之前的博客 阿里云服务器上搭载 FTP 站点 本篇博客记录:如何通过java 实现FTP文件上传下载和删除功能。虽然网上有很多教程,但是或多或少都会有些问题。看到本篇文章,也许会让你少踩坑哦~

二、开发环境
  • IDEA 2017.3.5
  • Maven 3.5
  • JDK 1.8
三、步骤详情
3.1、通过Apache FTP工具类实现文件上传下载以及删除

pom.xml 文件中,添加对应依赖:

代码语言:javascript复制
<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.3</version>
</dependency>

代码中使用到单元测试,需添加依赖:

代码语言:javascript复制
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
</dependency>
3.2、直接上代码

创建一个 FtpUtil 类:

代码语言:javascript复制
package com.xmlvhy.ftp;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.junit.Assert;
import org.junit.Test;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Author: 小莫
 * Date: 2019-03-15 10:53
 * Description: ftp 文件上传下载删除工具类
 */
public class FtpUtil {

    /**
     * Description: 向FTP服务器上传文件
     *
     * @param url      FTP服务器hostname
     * @param port     FTP服务器端口
     * @param username FTP登录账号
     * @param password FTP登录密码
     * @param path     FTP服务器保存目录
     * @param filename 上传到FTP服务器上的文件名
     * @param input    输入流
     * @return 成功返回true,否则返回false
     */
    public static Map<String, Object> uploadFile(String url, int port, String username, String password, String path, String filename, FileInputStream input) {
        boolean success = false;
        Map<String, Object> map = new HashMap<>();
        String filepath = "";
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(url, port);//连接FTP服务器
            //如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            ftp.login(username, password);//登录
            reply = ftp.getReplyCode();

            //判断reply的code是否正常,一般正常为2开头的code
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                map.put("status", success);
                map.put("filepath", filepath);
                return map;
            }

            boolean a = ftp.changeWorkingDirectory("/");
            System.out.println("转换目录结果1:"   a);

            String basePath = "/";
            path = "static/images/20190315";
            if (path == null || path.equals("/")) {//如果输入的路径为空或者为根路径,则不转换操作目录

            } else {//否则创建想要上传文件的目录,并且将操作目录转为新创建的目录

                //如果目录不存在创建目录
                String[] dirs = path.split("/");
                String tempPath = basePath;
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)) continue;
                    tempPath  = "/"   dir;
                    if (!ftp.changeWorkingDirectory(tempPath)) {
                        if (!ftp.makeDirectory(tempPath)) {
                            success = false;
                        } else {
                            boolean b = ftp.changeWorkingDirectory(tempPath);
                            System.out.println("转换目录结果2:"   b);
                        }
                    }
                }

                //ftp.makeDirectory(path);
                //boolean b = ftp.changeWorkingDirectory(path);
                //System.out.println("转换目录结果2:" b);
            }

            //ftp上传文件是以文本形式传输的,所以多媒体文件会失真,需要转为二进制形式传输
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //转码后可以文件名可以为中文
            ftp.storeFile(new String(filename.getBytes("GBK"), "iso-8859-1"), input);
            input.close();
            ftp.logout();
            success = true;
            filepath = "ftp://"   url   ":"   port   "/"   path   "/"   filename;
            map.put("status", success);
            map.put("filepath", filepath);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (Exception ioe) {

                }
            }
        }
        return map;
    }

    /**
     * Description: 从FTP服务器下载文件
     *
     * @param host       FTP服务器hostname
     * @param port       FTP服务器端口
     * @param username   FTP登录账号
     * @param password   FTP登录密码
     * @param remotePath FTP服务器上的相对路径
     * @param fileName   要下载的文件名
     * @param localPath  下载后保存到本地的路径
     * @return
     */
    public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
                                       String fileName, String localPath) {
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
            ftp.login(username, password);// 登录
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return result;
            }
            ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    File localFile = new File(localPath   "/"   ff.getName());

                    OutputStream is = new FileOutputStream(localFile);
                    ftp.retrieveFile(ff.getName(), is);
                    is.close();
                }
            }

            ftp.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

    /**
     * Description: 从FTP服务器删除文件
     *
     * @param host       FTP服务器hostname
     * @param port       FTP服务器端口
     * @param username   FTP登录账号
     * @param password   FTP登录密码
     * @param remotePath FTP服务器上的相对路径
     * @param fileName   要删除的文件名
     * @return
     */
    public static boolean deleteFile(String host, int port, String username, String password, String remotePath,
                                     String fileName) {
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
            ftp.login(username, password);// 登录
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return result;
            }
            ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    ftp.deleteFile(fileName);
                }
            }
            //退出登录
            ftp.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }
}

再创建一个FtpTest 类,对 FtpUtil 中的方法进行测试

代码语言:javascript复制
package com.xmlvhy.ftp;

import org.junit.Assert;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * Author: 小莫
 * Date: 2019-03-18 15:24
 * Description: ftp 工具类测试
 */
public class TtpTest {

    /**
     *功能描述: 上传文件
     * @Author 小莫
     * @Date 15:26 2019/03/18
     * @Param []
     * @return void
     */
    @Test
    public void test1() {
        try {
            FileInputStream in = new FileInputStream(new File("F:/user.png"));
            String filePath = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String fileName = "user.png";
            Map<String, Object> map = FtpUtil.uploadFile("您的服务器域名", 21, "ftptest", "ftp账户密码", filePath, fileName, in);
            System.out.println(map.get("status")   "====>"   map.get("filepath"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     *功能描述: 下载文件
     * @Author 小莫
     * @Date 15:26 2019/03/18
     * @Param []
     * @return void
     */
    @Test
    public void test2() {
        boolean flag = FtpUtil.downloadFile("您的服务器域名", 21, "ftptest", "ftp账户密码", "/", "user.png", "E:/");
        Assert.assertEquals(true, flag);
    }


    /**
     *功能描述: 删除文件
     * @Author 小莫
     * @Date 15:26 2019/03/18
     * @Param []
     * @return void
     */
    @Test
    public void test3() {
        boolean flag = FtpUtil.deleteFile("您的服务器域名", 21, "ftptest", "ftp账户密码", "static/images/20190315", "user.png");
        Assert.assertEquals(true, flag);
    }
}

测试类中参数的相关说明

  • 文件上传测试模块:我是本地 F 盘中有 ‘user.png’ 文件,这里注意修改您的路径文件;
  • 特别注意:ftp 登录进去默认是到您 ftp 服务器的根路径,这里 ftp服务器的根路径以及 remotePath 都是 "/" ,这个路径一定要对,要不然多层级目录上传文件时候, makeDirectory(...)这个方法一直返回false,上传失败,我也是卡在这。当时还各种怀疑 ftp 服务器的配置啊,目录权限啊是不是有问题,卡了蛮久~

备注:

  • changeWorkingDirectory()方法,是用来切换目录的,如果切换目录成功则返回 true,反之返回 false
  • makeDirectory() 方法,是用来创建目录,该方法注意:只能创建一次目录(如果有多层目录的,则需要通过一层一层的去创建);如果当前存在目录则返回 true,反之如果创建失败则返回 false ;
代码语言:javascript复制
			//ftp站点的根目录,也就是你ftp账户登录成功进入到的目录
			String basePath = "/";
			//文件所要上传的路径,这个目录根据自己设定
            path = "static/images/20190315";
            if (path == null || path.equals("/")) {//如果输入的路径为空或者为根路径,则不转换操作目录

            } else {//否则创建想要上传文件的目录,并且将操作目录转为新创建的目录
                //如果目录不存在创建目录
                String[] dirs = path.split("/");
                String tempPath = basePath;
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)) continue;
                    tempPath  = "/"   dir;
                    if (!ftp.changeWorkingDirectory(tempPath)) {
                        if (!ftp.makeDirectory(tempPath)) {
                            success = false;
                        } else {
                            boolean b = ftp.changeWorkingDirectory(tempPath);
                            System.out.println("转换目录结果2:"   b);
                        }
                    }
                }
            }
四、测试结果
4.1、运行 test1() 方法上传一个文件

可以看到,文件成功上传到设定的目录中去了。删除 和 下载功能类似,只是调用的方法不一样,这里便不再展示结果了~

本篇博客涉及的代码 获取源码

本文作者: AI码真香

本文标题: JAVA 实现 FTP 文件上传、下载和删除

本文网址: https://www.xmlvhy.com/article/67.html

版权说明: 自由转载-非商用-非衍生-保持署名 署名-非商业性使用4.0 国际 (CC BY-NC 4.0)

0 人点赞