SFTP上传

157 阅读3分钟

实现SFTP的两种方式

手动上传

  1. 下载Cyberduck
  2. 新建连接

image.png

3.选择SFTP协议,输入ip、用户名、密码/密钥

image.png

  1. 连接成功
  2. 文件下载:右击文件选择另存为[本地目录]
  3. 文件上传:粘贴本地文件,复制到窗口中,实现传输

Java上传

  1. 依赖于JSch,其代理了SSH的功能,官网
  2. 也可以到仓库查询依赖
  3. 这里使用Gradle构建implementation 'com.jcraft:jsch:0.1.55'
  4. 编写SFTP工具类
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import org.apache.commons.lang.StringUtils;

import java.io.InputStream;
import java.util.Properties;

/**
 * SFTP 工具类
 */
public final class SftpUtils {
    /**
     * 私有化
     */
    private SftpUtils() {}

    /**
     * create session
     *
     * @param sftpHost 主机地址
     * @param sftpUsername 用户名
     * @param sftpPrivateKeyFile 密钥
     * @param sftpPassword 密码
     * @return session
     * @throws JSchException JSchExp
     */
    public static Session connect(String sftpHost, String sftpUsername, String sftpPrivateKeyFile,
                                  String sftpPassword) throws JSchException {
        JSch jSch = new JSch();

        // 密钥非空时,使用密钥验证
        if (StringUtils.isNotEmpty(sftpPrivateKeyFile)) {
            jSch.addIdentity(sftpPrivateKeyFile); // 密钥路径
        }
        
        // SSH默认TCP端口22
        Session session = jSch.getSession(sftpUsername, sftpHost);

        // 设置密码
        if (StringUtils.isNotEmpty(sftpPrivateKeyFile)) {
            session.setUserInfo(new SftpUserInfo(sftpPrivateKeyFile));
        } else if (StringUtils.isNotEmpty(sftpPassword)) {
            session.setPassword(sftpPassword);
        }

        // 每次远程登录Linux的时候,Linux都要检查一下,当前访问的计算机公钥是不是在~/.ssh/know_hosts中,
        // 禁止检查,避免无法连接SSH,虽然这样做尽管会不安全
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setTimeout(60 * 1000); // 1分钟超时,单位:milliseconds,可修改
        session.connect();
        return session;
    }

    /**
     * open channel
     *
     * @param session session
     * @return 结果
     * @throws JSchException JSchExp
     */
    public static ChannelSftp openChannel(Session session) throws JSchException {
        Channel channel = session.openChannel("sftp");
        channel.connect();
        return (ChannelSftp) channel;
    }

    /**
     * channel断开连接
     *
     * @param channelSftp channelSftp
     */
    public static void disconnect(ChannelSftp channelSftp) {
        if (null != channelSftp && channelSftp.isConnected()) {
            channelSftp.disconnect();
        }
    }

    /**
     * session断开连接
     *
     * @param session session
     */
    public static void disconnect(Session session) {
        if (null != session && session.isConnected()) {
            session.disconnect();
        }
    }

    /**
     * 上传
     *
     * @param channelSftp SFTP链接
     * @param src 源文件地址
     * @param dst 目标文件地址
     * @throws SftpException SftpExp
     */
    public static void upload(ChannelSftp channelSftp, InputStream src, String dst) throws SftpException {
        channelSftp.put(src, dst);
    }

    /**
     * 下载
     *
     * @param channelSftp SFTP链接
     * @param src 源文件地址
     * @param dst 目标文件地址
     * @throws SftpException SftpExp
     */
    public static void download(ChannelSftp channelSftp, String src, String dst) throws SftpException {
        channelSftp.get(src, dst);
    }
}
  1. 上传功能
// 需要上传的文件,源文件
File file = new File("/Users/xxx/xxx.txt");

// 建立SFTP链接
Session session = null;
ChannelSftp channelSftp = null;
try {
    String sftpHost = "您的文件服务器IP";
    String sftpUsername = "您的文件服务器登陆用户名";
    String sftpPrivateKey = "您的SSH密钥";
    String sftpPassword = "您的文件服务器登陆密码,此处与SSH密钥二选一";
    
    session = SftpUtils.connect(sftpHost, sftpUsername, sftpPrivateKey, sftpPassword);
    channelSftp = SftpUtils.openChannel(session);

    // 上传源文件
    InputStream is = new FileInputStream(file);
    SftpUtils.upload(channelSftp, is, "/root/" + fileName);
    
} catch (JSchException | SftpException e) {
    e.printStackTrace();
}  finally {
    // 切记关闭channel后要关闭session
    SftpUtils.disconnect(channelSftp);
    SftpUtils.disconnect(session);
}
  1. 下载功能
ChannelSftp channelSftp = null;
Session session = null;

try {
    String sftpHost = "您的文件服务器IP";
    String sftpUsername = "您的文件服务器登陆用户名";
    String sftpPrivateKey = "您的SSH密钥";
    String sftpPassword = "您的文件服务器登陆密码,此处与SSH密钥二选一";
    
    session = SftpUtils.connect(sftpHost, sftpUsername, sftpPrivateKey, sftpPassword);
    channelSftp = SftpUtils.openChannel(session);
    
    SftpUtils.download(channelSftp, "/root/test.txt", "/Users/xxxx/Desktop/file/");
    // 重命名文件可以写清文件名
    // SftpUtils.download(channelSftp, "/root/test.txt", "/Users/xxxx/Desktop/file/xxx.txt");

} catch (JSchException | SftpException e) {
    e.printStackTrace();
} finally {
    SftpUtils.disconnect(channelSftp);
    SftpUtils.disconnect(session);
}
  1. 对于工具类中的类SftpUserInfo, 继承了JSch的类UserInfo,这是必须的
import com.jcraft.jsch.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JSch 登陆信息
 */
public class SftpUserInfo implements UserInfo {
    /**
     * Logger
     */
    private static final Logger logger = LoggerFactory.getLogger(SftpUserInfo.class);

    /**
     * ssh private key passphrase
     */
    private String passphrase;

    /**
     * 构造函数需要传秘钥的路径,是秘钥的文件路径,不是流也不是秘钥内容
     */
    public SftpUserInfo (String passphrase) {
        this.passphrase = passphrase;
    }

    @Override
    public String getPassphrase() {
        return passphrase;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public boolean promptPassword(String message) {
        return false;
    }

    @Override
    public boolean promptPassphrase(String message) {
        return true;
    }

    @Override
    public boolean promptYesNo(String message) {
        return true;
    }

    @Override
    public void showMessage(String message) {
        logger.info ("SSH Message:{}", message);
    }
}