SFTP Java协议应用

2022-07-31,,

  · FTP服务器搭建

  本文使用Win10搭建的SFTP服务器,关于Win10下SFTP服务器的搭建,搭建可以参考本博的另一篇博文《Win10 基于FreeSSHd搭建SFTP服务 配置详解》。

  · Maven 依赖

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

  · SFTP 工具类

package com.arhorchin.securitit.protocol.sftp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Properties;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

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;

/**
 * @author Securitit.
 * @note SFTP协议连接共享文件夹.
 */
public class SftpUtil {

    /**
     * logger.
     */
    private Logger logger = Logger.getLogger(SftpUtil.class);

    /**
     * sftp.
     */
    private ChannelSftp sftp;

    /**
     * session.
     */
    private Session session;

    /**
     * SFTP 登录用户名.
     */
    private String username;

    /**
     * SFTP 登录密码.
     */
    private String pp;

    /**
     * 私钥.
     */
    private String privateKey;

    /**
     * SFTP 服务器地址IP地址.
     */
    private String host;

    /**
     * SFTP 端口.
     */
    private int port;

    /**
     * 构造基于密码认证的sftp对象.
     * @param username .
     * @param pp .
     * @param host .
     * @param port .
     */
    public SftpUtil(String username, String pp, String host, int port) {
        this.username = username;
        this.pp = pp;
        this.host = host;
        this.port = port;
    }

    /**
     * 构造基于秘钥认证的sftp对象.
     * @param username .
     * @param host .
     * @param port .
     * @param privateKey .
     */
    public SftpUtil(String username, String host, int port, String privateKey) {
        this.username = username;
        this.host = host;
        this.port = port;
        this.privateKey = privateKey;
    }

    /**
     * 连接sftp服务器.
     */
    public void sftpLogin() throws Exception {
        JSch jsch = null;
        Properties config = null;
        Channel channel = null;

        try {
            JSch.setLogger(new SftpLogger());
            jsch = new JSch();
            // 设置私钥.
            if (privateKey != null) {
                jsch.addIdentity(privateKey);
            }
            session = jsch.getSession(username, host, port);
            // 设置密码.
            if (pp != null) {
                session.setPassword(pp);
            }
            config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            config.put("PreferredAuthentications", "password");

            session.setConfig(config);
            session.connect(10000);

            channel = session.openChannel("sftp");
            channel.connect();

            sftp = (ChannelSftp) channel;
        } catch (JSchException ex) {
            logger.error(ex);
            throw new Exception(ex);
        }
    }

    /**
     * 关闭连接 server.
     */
    public void sftpLogout() {
        if (sftp != null) {
            if (sftp.isConnected()) {
                sftp.disconnect();
            }
        }
        if (session != null) {
            if (session.isConnected()) {
                session.disconnect();
            }
        }
    }

    /**
     * 上传文件.
     * @param sftpBasepath 基础目录.
     * @param sftpFilename 文件名称.
     * @param fileBytes 文件内容.
     * @throws SftpException .
     * @return 上传结果.
     */
    public boolean sftpUpload(String sftpBasepath, String sftpFilename, byte[] fileBytes) throws Exception {
        ByteArrayInputStream sftpFileBais = null;

        try {
            sftp.cd(sftp.getHome());
            if (!StringUtils.isEmpty(sftpBasepath)) {
                sftpMkdir(sftpBasepath);
            }
            sftpFileBais = new ByteArrayInputStream(fileBytes);
            sftp.put(sftpFileBais, sftpFilename);
            return true;
        } catch (SftpException ex) {
            logger.error(ex);
            return false;
        }
    }

    /**
     * 下载文件.
     * @param sftpBasepath 基础目录.
     * @param sftpFilename 文件名称.
     * @throws SftpException .
     * @throws FileNotFoundException.
     * @return 下载文件.
     */
    public byte[] download(String sftpBasepath, String sftpFilename) throws Exception {
        ByteArrayOutputStream sftpFileBaos = null;

        try {
            sftp.cd(sftp.getHome());
            if (!StringUtils.isEmpty(sftpBasepath)) {
                sftpMkdir(sftpBasepath);
            }
            sftpFileBaos = new ByteArrayOutputStream();
            sftp.get(sftpFilename, sftpFileBaos);
            return sftpFileBaos.toByteArray();
        } catch (Exception ex) {
            logger.error(ex);
            return null;
        }
    }

    /**
     * 删除文件.
     * @param sftpBasepath 基础目录.
     * @param sftpFilename 文件名称.
     * @throws SftpException.
     * @return 删除结果.
     */
    public boolean delete(String sftpBasepath, String sftpFilename) throws Exception {
        try {
            sftp.cd(sftp.getHome());
            if (!StringUtils.isEmpty(sftpBasepath)) {
                sftpMkdir(sftpBasepath);
            }
            sftp.rm(sftpFilename);
            return true;
        } catch (Exception ex) {
            logger.error(ex);
            return false;
        }
    }

    /**
     * 列出目录下的文件.
     * @param sftpDirectory 目录.
     * @return 目录内容.
     * @throws SftpException .
     */
    public Vector<?> sftpListFiles(String sftpDirectory) throws Exception {
        return sftp.ls(sftpDirectory);
    }

    /**
     * 创建多层目录.
     * @param sftpPath .
     * @throws Exception .
     */
    public void sftpMkdir(String sftpPath) throws Exception {
        try {
            sftp.cd(sftpPath);
        } catch (SftpException e) {
            String[] dirs = sftpPath.split("/");
            String tempPath = sftp.getHome();
            for (String dir : dirs) {
                if (null == dir || "".equals(dir))
                    continue;
                tempPath += "/" + dir;
                try {
                    sftp.cd(tempPath);
                } catch (SftpException ex) {
                    sftp.mkdir(tempPath);
                    sftp.cd(tempPath);
                }
            }
        }
    }

}

  · 测试类如下:

package com.arhorchin.securitit.protocol.sftp;

import java.io.File;

import org.apache.commons.io.FileUtils;

/**
 * @author Securitit.
 * @note SftpUtil测试.
 */
public class SftpUtilTester {

    public static void main(String[] args) throws Exception {
        String sftpIp = "192.168.120.1";
        Integer sftpPort = 22;
        String sftpUsername = "sftp";
        String sftpPassword = "123456";

        SftpUtil sftp = null;
        // 登录SFTP服务器.
        sftp = new SftpUtil(sftpUsername, sftpPassword, sftpIp, sftpPort);
        sftp.sftpLogin();
        // 上传文件.
        byte[] fileBytes = FileUtils.readFileToByteArray(new File("C:/Users/Administrator/Downloads/个人文件/test.pdf"));
        sftp.sftpUpload("/Test", "test.pdf", fileBytes);
        // 下载文件.
        fileBytes = sftp.sftpDownload("/Test", "test.pdf");
        System.out.println("下载文件大小:" + fileBytes.length);
        // 删除文件.
        sftp.sftpDelete("/Test", "test.pdf");
        // 退出SFTP登录.
        sftp.sftpLogout();
    }

}

  · 总结

  · 监控服务器SFTP物理路径可以看到文件的变化。

  · 测试类输出内容中,可以看到下载的文件长度,说明下载成功了。

  · SftpUtil工具类可以拿来直接使用,本人已进行过简单测试。

  · com.jcraft.jsch.JSchException: Auth fail 如果发生Auth fail,则需要检查自己的配置,按照如下配置检查:

    ① 首先确认FreeSSHd以管理员方式启动

    ② 对FreeSSHd用户进行重新设置:重新启动FreeSSHd进程,使用删除+新增操作代替修改用户操作,删除用户,然后新增用户并设置认证方式和权限等信息,最后启动服务。

本文地址:https://blog.csdn.net/securitit/article/details/107590372

《SFTP Java协议应用.doc》

下载本文的Word格式文档,以方便收藏与打印。