Java从ftp服务器上传与下载文件

一、背景

业务需要从ftp服务器上上传、下载、删除文件等功能,通过查阅资料及手动敲打代码,实现了操作ftp的基本功能,有需求的小伙伴可以看看具体的实现过程。

二、ftp介绍

摘自百度百科:文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,FTP允许用户以文件操作的方式(如文件的增、删、改、查、传送等)与另一主机相互通信。

三、具体代码实现

1、引入以下依赖

<!--apache下,包含连接ftp服务器的工具-->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.6</version>
</dependency>

2、编写一个FTP工具类

含以下四个方法:

*获取一个FtpClinet连接

*关闭FtpClinet连接

*下载文件

*上传文件

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.nio.charset.StandardCharsets;

@Slf4j
public class FtpUtil {

    /**
     * 获取一个ftp连接
     * @param host ip地址
     * @param port 端口
     * @param username 用户名
     * @param password 密码
     * @return 返回ftp连接对象
     * @throws Exception 连接ftp时发生的各种异常
     */
    public static FTPClient getFtpClient(String host, Integer port, String username, String password) throws Exception{
        FTPClient ftpClient = new FTPClient();

        // 连接服务器
        ftpClient.connect(host, port);

        int reply = ftpClient.getReplyCode();
        if(!FTPReply.isPositiveCompletion(reply)){
            log.error("无法连接至ftp服务器, host:{}, port:{}", host, port);
            ftpClient.disconnect();
            return null;
        }

        // 登入服务器
        boolean login = ftpClient.login(username, password);
        if(!login){
            log.error("登录失败, 用户名或密码错误");
            ftpClient.logout();
            ftpClient.disconnect();
            return null;
        }

        // 连接并且成功登陆ftp服务器
        log.info("login success ftp server, host:{}, port:{}, user:{}", host, port, username);

        // 设置通道字符集, 要与服务端设置一致
        ftpClient.setControlEncoding("UTF-8");
        // 设置文件传输编码类型, 字节传输:BINARY_FILE_TYPE, 文本传输:ASCII_FILE_TYPE, 建议使用BINARY_FILE_TYPE进行文件传输
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        // 动模式: enterLocalActiveMode(),被动模式: enterLocalPassiveMode(),一般选择被动模式
        ftpClient.enterLocalPassiveMode();
        // 切换目录
        //ftpClient.changeWorkingDirectory("xxxx");

        return ftpClient;
    }

    /**
     * 断开ftp连接
     * @param ftpClient ftp连接客户端
     */
    public static void disConnect(FTPClient ftpClient){
        if(ftpClient == null){
            return;
        }
        try {
            log.info("断开ftp连接, host:{}, port:{}", ftpClient.getPassiveHost(), ftpClient.getPassivePort());
            ftpClient.logout();
            ftpClient.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ftp连接断开异常, 请检查");
        }

    }

    /**
     * 文件下载
     * @param ftpClient ftp连接客户端
     * @param path 文件路径
     * @param fileName 文件名称
     */
    public static void download(FTPClient ftpClient, String path, String fileName) throws Exception {
        if(ftpClient == null || path == null || fileName == null){
            return;
        }

        // 中文目录处理存在问题, 转化为ftp能够识别中文的字符集
        String remotePath;
        try {
            remotePath = new String(path.getBytes(StandardCharsets.UTF_8), FTP.DEFAULT_CONTROL_ENCODING);
        } catch (UnsupportedEncodingException e) {
            remotePath = path;
        }

        InputStream inputStream = ftpClient.retrieveFileStream(remotePath);
        if (inputStream == null) {
            log.error("{}在ftp服务器中不存在,请检查", path);
            return;
        }

        FileOutputStream outputStream = new FileOutputStream("D:\\test\\" + fileName);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
        try{
            byte[] buffer = new byte[2048];
            int i;
            while ((i = bufferedInputStream.read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, i);
                bufferedOutputStream.flush();
            }
        } catch (Exception e) {
            log.error("文件下载异常", e);
            log.error("{}下载异常,请检查", path);
        }

        inputStream.close();
        outputStream.close();
        bufferedInputStream.close();
        bufferedOutputStream.close();

        // 关闭流之后必须执行,否则下一个文件导致流为空
        boolean complete = ftpClient.completePendingCommand();
        if(complete){
            log.info("文件{}下载完成", remotePath);
        }else{
            log.error("文件{}下载失败", remotePath);
        }

    }

    /**
     * 上传文件
     * @param ftpClient ftp连接客户端
     * @param sourcePath 源地址
     */
    public static void upload(FTPClient ftpClient, String sourcePath) throws Exception{
        if(ftpClient == null || sourcePath == null){
            return;
        }

        File file = new File(sourcePath);
        if(!file.exists() || !file.isFile()){
            return;
        }

        // 中文目录处理存在问题, 转化为ftp能够识别中文的字符集
        String remotePath;
        try {
            remotePath = new String(file.getName().getBytes(StandardCharsets.UTF_8), FTP.DEFAULT_CONTROL_ENCODING);
        } catch (UnsupportedEncodingException e) {
            remotePath = file.getName();
        }
        
        try(
                InputStream inputStream = new FileInputStream(file);
                OutputStream outputStream = ftpClient.storeFileStream(remotePath);
        ){
            byte[] buffer = new byte[2048];
            int length;
            while((length = inputStream.read(buffer)) != -1){
                outputStream.write(buffer, 0, length);
                outputStream.flush();
            }
        }catch (Exception e){
            log.error("文件上传异常", e);
        }

        // 关闭流之后必须执行,否则下一个文件导致流为空
        boolean complete = ftpClient.completePendingCommand();
        if(complete){
            log.info("文件{}上传完成", remotePath);
        }else{
            log.error("文件{}上传失败", remotePath);
        }


    }
}

3、测试连接、上传文件、下载文件、关闭连接功能

@Slf4j
@RestController
public class FtpController {

    private static final String FTP_HOST = "your host";

    private static final Integer FTP_PORT = 21;

    private static final String FTP_USERNAME = "your username";

    private static final String FTP_PASSWORD = "your password";

    @GetMapping("/test")
    public void test() throws Exception{

        FTPClient ftpClient = FtpUtil.getFtpClient(FTP_HOST, FTP_PORT, FTP_USERNAME, FTP_PASSWORD);

        // 展示文件夹
        FTPFile[] ftpFiles = ftpClient.listDirectories();
        for(FTPFile file : ftpFiles){
            System.out.println(file.getName());
        }

        // 下载文件
        FtpUtil.download(ftpClient, "test.txt", "test.txt");

        //FtpUtil.download(ftpClient, "test.py", "test.py");
        // 上传文件
        FtpUtil.upload(ftpClient, "D:\\test\\test.py");


        FtpUtil.disConnect(ftpClient);

    }


}

经过测试,能够正常连接上ftp服务器,并且上传下载文件,最后关闭连接。

四、遇到的问题

在使用过程中,遇到以下问题,需要记录一下,以防下次忘记:

就是在创建完一个FtpClient连接之后,关闭连接之前,第一次进行文件上传或下载是正常的,当第二次进行文件上传或下载时,从FtpClient获取的输入流或输出流是空的。需要在每次操作完文件上传或下载时,添加上以下代码片段:

// 关闭流之后必须执行,否则下一个文件导致流为空
boolean complete = ftpClient.completePendingCommand();
if(complete){
    log.info("文件{}下载完成", remotePath);
}else{
    log.error("文件{}下载失败", remotePath);
}

该方法有以下注释:

There are a few FTPClient methods that do not complete the entire sequence 
of FTP commands to complete a transaction. These commands require some action 
by the programmer after the reception of a positive intermediate command. 
After the programmer's code completes its actions, it must call this method 
to receive the completion reply from the server and verify the success of the 
entire transaction.

百度翻译大致意思应该是:有一些FTPClient方法不能完成完成事务的整个FTP命令序列。这些命令需要程序员在接收到肯定的中间命令后采取一些行动。程序员的代码完成其操作后,必须调用此方法以从服务器接收完成回复,并验证整个事务的成功。

这里不知道是不是描述的我这种情况, completePedingCommand的意思是完成挂起命令。可能我们当前场景就符合。刚兴趣的小伙伴可以深入去探讨一下。

五、参考连接

https://blog.csdn.net/AndyWei147/article/details/90745518

https://blog.csdn.net/weixin_39981289/article/details/128614774

要实现从前端上传下载PDF文件FTP服务器,可以使用Java编程语言和FTP客户端库。 首先,需要在前端创建一个文件上传表单,并设置相应的文件选择按钮、提交按钮和处理逻辑。用户选择要上传的PDF文件后,将文件发送给后端服务器。 接下来,后端使用Java编写一个处理上传文件的控制器。控制器接收到文件后,使用FTP客户端库连接到FTP服务器。可以使用Apache Commons Net库中提供的FTPClient类。通过FTPClient,可以使用connect()方法连接到FTP服务器,使用login()方法提供用户名和密码进行登录验证,使用setFileType()方法设置文件类型为二进制,并使用storeFile()方法将文件存储到FTP服务器指定的路径。 要实现从FTP服务器下载PDF文件,可以在前端创建一个下载按钮,用户点击按钮后,发起对控制器的请求。后端代码中,使用FTPClient连接到FTP服务器后,使用retrieveFile()方法从服务器下载指定的PDF文件到本地。 在实现上传下载的过程中,需要注意异常处理和文件路径的设置。确保FTP服务器的地址、端口、用户名和密码正确,并确保FTP服务器的路径正确。 在整个过程中,还需要考虑文件的命名策略和权限管理。可以在上传文件时为文件生成唯一的文件名,避免文件冲突。此外,还可以设置FTP服务器的权限,确保上传文件只能被授权的用户访问和下载。 通过以上步骤,就可以使用Java实现从前端上传下载PDF文件FTP服务器了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值