# Java Ftp 文件上传下载

环境准备
  • Win10 搭建 ftp
Ftp 端口
  • 21端口:命令端口
  • 20端口:FTP传输数据端口,是否会用到20端口与FTP传输模式有关,主动模式使用20端口传输,被动模式下服务器端和客户端协商决定端口。
Ftp 主动模式、被动模式

​ Ftp支持两种方式的传输:文本(ASCII)方式和二进制(Binary)方式,通常文本文件的传输采用ASCII方式,图像、声音文件等非文本文件采用二进制方式传输。

  • 主动模式:客户端向Ftp服务器端发送端口信息,由服务器主动连接该端口。

  • 被动模式:FTP服务器开启并发送端口信息给客户端,由客户端连接该端口,服务器被动接受连接。

添加依赖
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.3</version>
</dependency>
FtpUtils
/**
 * @author lidong
 */
public class FtpUtils {

    private static final Logger logger = LoggerFactory.getLogger(FtpUtils.class);

    /**
     * @param ftpUrl      ftp 主机地址
     * @param ftpUserName 用户名
     * @param ftpPassword 密码
     * @param port        端口号
     * @return
     */
    public static FTPClient getFtpClient(String ftpUrl, String ftpUserName, String ftpPassword, int port) {
        FTPClient ftpClient = new FTPClient();
        try {
            // 获取连接
            ftpClient.connect(ftpUrl, port);
            // 登录
            ftpClient.login(ftpUserName, ftpPassword);
            int reply;
            reply = ftpClient.getReplyCode();
            if (FTPReply.isPositiveCompletion(reply)) {
                logger.info("成功登录 ftp 服务器...");
                logger.info("成功登录服务器,被动模式主机:[{}:{}]", ftpClient.getPassiveHost(), ftpClient.getPassivePort());
                logger.info("成功登录服务器,主动模式主机:[{}:{}]", ftpClient.getRemoteAddress(), ftpClient.getRemotePort());
                logger.info("成功登录服务器,本地主机:[{}:{}]", ftpClient.getLocalAddress(), ftpClient.getLocalPort());
                logger.info("成功登录服务器,返回代码:[{}], 显示状态[{}]", ftpClient.getReplyCode(), ftpClient.getStatus());
            } else {
                ftpClient.disconnect();
                logger.info("Ftp 登录之后的 ReplyCode{}:", ftpClient.getReplyCode());
            }
            // 解决创建的文件含有汉字乱码问题
            ftpClient.setControlEncoding("UTF-8");
            // 设置成以二进制传输
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return ftpClient;
    }

    /**
     * 获得 Ftp 上文件的流
     *
     * @param ftpClient        ftp 连接对象
     * @param ftpPathDirectory ftp 上文件目录
     * @param fileName         文件名称
     * @return
     * @throws IOException
     */
    public static InputStream getFtpInputStream(FTPClient ftpClient, String ftpPathDirectory, String fileName) throws IOException {
        InputStream inputStream = null;
        boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(ftpPathDirectory);
        if (!changeWorkingDirectory) {
            throw new IllegalArgumentException("当前文件夹不存在!");
        }
        /**
         * 主动模式传送数据时是“服务器”连接到“客户端”的端口;被动模式传送数据是“客户端”连接到“服务器”的端口
         * 主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
         * 被动模式只需要服务器端开放端口给客户端连接就行了。
         */
        // 被动模式
        ftpClient.enterLocalPassiveMode();
        try {
            inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        } catch (Exception e) {
            logger.error("Error Occur{}:", e.getMessage());
        }
        if (inputStream == null) {
            // 主动模式
            ftpClient.enterLocalActiveMode();
            inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        }
        Objects.requireNonNull(inputStream);
        return inputStream;
    }

    /**
     * 下载 ftp 文件
     *
     * @param ftpClient
     * @param pathDirectory ftp 文件目录
     * @param fileName      ftp 文件名称
     * @param downLoadPath  下载路径
     * @return
     * @throws IOException
     */
    public static String downLoadFtpFile(FTPClient ftpClient, String pathDirectory, String fileName, String downLoadPath) throws IOException {
        boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(pathDirectory);
        if (!changeWorkingDirectory) {
            throw new IllegalArgumentException("当前文件目录不存在!");
        }
        // 文件绝对路径
        String fileFullPath = downLoadPath + fileName;
        File file = new File(fileFullPath);
        OutputStream outputStream = new FileOutputStream(file);
        for (FTPFile ftpFile : ftpClient.listFiles()) {
            String ftpFileName = ftpFile.getName();
            logger.info("目录:{} 下有文件:{}", pathDirectory, ftpFileName);
            if (ftpFileName.contains(fileName)) {
                ftpClient.retrieveFile(ftpFileName, outputStream);
                outputStream.close();
            }
        }
        return "下载成功,下载的文件路径为:" + fileFullPath;
    }

    /**
     * 文件上传
     *
     * @param ftpClient
     * @param ftpUploadPath 文件上传 ftp 目录
     * @param fileFullPath  本地文件 绝对路径
     * @return
     * @throws IOException
     */
    public static String uploadFtpFile(FTPClient ftpClient, String ftpUploadPath, String fileFullPath) throws IOException {
        boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(ftpUploadPath);
        if (!changeWorkingDirectory) {
            ftpClient.makeDirectory(ftpUploadPath);
            logger.info("在 ftp 下创建文件夹:{}", ftpUploadPath);
        }
        ftpClient.changeWorkingDirectory(ftpUploadPath);
        File file = new File(fileFullPath);
        InputStream inputStream = new FileInputStream(file);
        ftpClient.storeFile(file.getName(), inputStream);
        return "上传成功,上传的文件路径为:" + ftpUploadPath + file.getName();
    }


    /**
     * 列出指定目录下的文件
     *
     * @param ftpClient
     * @param filePathDirectory
     * @return
     */
    public static FTPFile[] listFtpFiles(FTPClient ftpClient, String filePathDirectory) throws IOException {
        boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(filePathDirectory);
        if (!changeWorkingDirectory) {
            throw new IllegalArgumentException("当前目录不存在!");
        }
        return ftpClient.listFiles();
    }


    private FTPClient getFtpClient() {
        String url = "100.100.100.100";
        int port = 21;
        String username = "admin";
        String password = "199917LD";
        return getFtpClient(url, username, password, port);
    }

    @Test
    public void testDownLoad() {
        try {
            String message = downLoadFtpFile(getFtpClient(), "/20210704/", "test_metadata20210701012856.xml", "D:\\迅雷云盘\\");
            logger.info(message);
        } catch (IOException e) {
            logger.error("Error Occur:{}", e.getMessage());
        }
    }

    @Test
    public void testUpLoad() {
        try {
            String message = uploadFtpFile(getFtpClient(), "/test/", "C:\\windows-version.txt");
            logger.info(message);
        } catch (IOException e) {
            logger.error("Error Occur:{}", e.getMessage());
        }
    }

    @Test
    public void testListFiles() {
        try {
            FTPFile[] ftpFiles = listFtpFiles(getFtpClient(), "/test");
            for (FTPFile ftpFile : ftpFiles) {
                logger.info(ftpFile.getName());
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

}
Ftps 更加安全的Ftp服务
  • 注意构造函数一定要加上 true默认是false
FTPSClient ftpsClient = null;
//创建一个ftp客户端
ftpsClient = new FTPSClient("SSL", true);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值