Java 调用 FTP 服务

239 阅读2分钟

使用 JAVA 代码对 FTP 进行上传、下载文件操作 方式一:

  1. 增加依赖

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

  1. 代码
package com.wheelmouse.ftp.service.impl;

import com.jcraft.jsch.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * 同名文件上传是覆盖操作。
 * 文件路径是不存在则创建,存在直接就可以上传。
 *
 * @author wheelmouse
 * @date 2024/11/22
 * @apiNote
 */
@Component
public class SftpServiceImpl {

    @Value("${sftp.host}")
    private String host;

    @Value("${sftp.port}")
    private int port;

    @Value("${sftp.username}")
    private String username;

    @Value("${sftp.password}")
    private String password;

    public Session connect() throws JSchException {
        JSch jsch = new JSch();
        Session session = jsch.getSession(username, host, port);
        session.setPassword(password);
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect();
        return session;
    }

    private void disconnect(ChannelSftp channel, Session session) {
        if (channel != null) {
            channel.exit();
        }
        if (session != null) {
            session.disconnect();
        }
    }

    /**
     * @param localFilePath  源文件路径+文件名
     * @param remoteFilePath 上传到sftp之后的文件名称
     * @param filePath       上传到sftp的路径
     */
    public void upload(String localFilePath, String remoteFilePath, String filePath) {
        Session session = null;
        ChannelSftp channel = null;
        try {
            //创建SFTP连接
            session = connect();
            //创建SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
            //判断目标文件夹是否存在,如果不存在则创建
            try {
                SftpATTRS attrs = channel.lstat(filePath);
                if (attrs == null || !attrs.isDir()) {
                    createDirectories(channel, filePath);
                }
            } catch (SftpException f) {
                if (f.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                    //channel.mkdir(filePath);
                    createDirectories(channel, filePath);
                }
            }
            channel.cd(filePath);
            //上传文件
            channel.put(localFilePath, remoteFilePath);

        } catch (JSchException | SftpException e) {
            e.printStackTrace();
        } finally {
            //关闭通道和会话
            disconnect(channel, session);
        }
    }

     /**
     * 递归创建文件夹
     * @param channel
     * @param path
     * @throws SftpException
     */
    private void createDirectories(ChannelSftp channel, String path) throws SftpException {
        String[] parts = path.split("/");
        StringBuilder currentPath = new StringBuilder();

        for (String part : parts) {
            if (part.isEmpty()) {
                // 跳过空部分
                continue;
            }
            currentPath.append("/").append(part);
            try {
                SftpATTRS attrs = channel.lstat(currentPath.toString());
                if (attrs == null || !attrs.isDir()) {
                    channel.mkdir(currentPath.toString());
                }
            } catch (SftpException e) {
                if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                    channel.mkdir(currentPath.toString());
                }
            }
        }
    }

    public List<String> listFiles(String directory) {
        Session session = null;
        ChannelSftp channel = null;
        try {
            //创建SFTP连接
            session = connect();
            //创建SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
            //获取目录列表
            Vector<ChannelSftp.LsEntry> list = channel.ls(directory);
            List<String> fileNameList = new ArrayList<>();
            for (ChannelSftp.LsEntry lsEntry : list) {
                String fileName = lsEntry.getFilename();
                if (!fileName.equals(".") && !fileName.equals("..") && fileName.endsWith(".json")) {
                    fileNameList.add(fileName);
                }
            }
            return fileNameList;
        } catch (JSchException | SftpException e) {
            e.printStackTrace();
        } finally {
            //关闭通道和会话
            disconnect(channel, session);
        }
        return null;
    }

    /**
     * 下载文件
     * @param directory 目标文件所在目录
     * @param fileName 文件名
     * @param localDirectory 本地目录
     * @return
     */
    public File downloadFile(String directory, String fileName, String localDirectory) {
        Session session = null;
        ChannelSftp channel = null;
        File localFile = null;
        try {
            // 创建SFTP连接
            session = connect();
            // 创建SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();

            // 构建本地文件路径
            File localDir = new File(localDirectory);
            if (!localDir.exists()) {
                localDir.mkdirs();
            }
            localFile = new File(localDir, fileName);
            // 下载文件到本地
            FileOutputStream fos = new FileOutputStream(localFile);
            channel.get(directory + "/" + fileName, fos);
            fos.close();
            return localFile;
        } catch (JSchException | SftpException | IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭通道和会话
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
        return null;
    }

    public InputStream get(String directory, String fileName) {
        Session session = null;
        ChannelSftp channel = null;
        try {
            //创建SFTP连接
            session = connect();
            //创建SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
            return channel.get(directory + "/" + fileName);
        } catch (JSchException | SftpException e) {
            e.printStackTrace();
        } finally {
            //关闭通道和会话
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
        return null;
    }

}

方式二:

  1. 增加依赖

<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.3</version>
</dependency>

  1. 代码

package com.wheelmouse.ftp.service.commons.utils;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* @Description ftp工具类
* @date 2018-03-22
*/
@Component
@Configuration
public class FtpUtil {
    
    // ftp服务器ip地址
    @Value("${spring.ftp.ip}")
    private String FTP_ADDRESS;
    // 端口号
    @Value("${spring.ftp.port}")
    private int FTP_PORT;
    // 用户名
    @Value("${spring.ftp.username}")
    private String FTP_USERNAME;
    // 密码
    @Value("${spring.ftp.password}")
    private String FTP_PASSWORD;
    
    public boolean uploadFile(String remoteDirectory, String remoteFileName, InputStream input) {
        boolean success = false;
        FTPClient ftp = new FTPClient();
        ftp.setControlEncoding("UTF-8");
        try {
            int reply;
            ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器
            ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return success;
            }
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 切换到指定目录
            ftp.makeDirectory(remoteDirectory);
            // 切换为本地被动模式,可以解决FTP上传后文件为空的问题,但需要服务器将FTP服务添加至防火墙白名单
            ftp.enterLocalPassiveMode();
            // // 切换到指定目录
            ftp.changeWorkingDirectory(remoteDirectory);
            ftp.storeFile(remoteFileName, input);
            input.close();
            ftp.logout();
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return success;
    }
    
}