一、SFTP使用场景

ftp是大多数网站的文件传输选择工具,但ftp并不是非常安全,并且在centos上搭建的vsftpd也非常的不稳定,偶尔会出现权限问题,例如500、或是账号密码不正确等等。

而SFTP是基于默认的22端口,是ssh内含的协议,只要启动了sshd就可以使用。

建议:更高的效率使用FTP协议,更安全的通信使用SFTP协议。

FTP是一种文件传输协议,一般是为了方便数据共享的。包括一个FTP服务器和多个FTP客户端。FTP客户端通过FTP协议在服务器上下载资源。而SFTP协议是在FTP的基础上对数据进行加密,使得传输的数据相对来说更安全。但是这种安全是以牺牲效率为代价的,也就是说SFTP的传输效率比FTP要低(不过现实使用当中,没有发现多大差别)。个人肤浅的认为就是:

FTP要安装,SFTP不要安装。
SFTP更安全,但更安全带来副作用就是的效率比FTP要低些。

二、SFTP工具类

这个工具类我写的比较粗糙,涉及到获取指定目录下的文件名,文件上传,文件写入,文件内容读取,文件下载,文件删除等.
此工具类有很多改进的地方…

import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.file.Files;
import java.util.Objects;
import java.util.Vector;

/**
 * Description: SFTP工具类
 * Create DateTime: 2022/10/17 17:07
 *
 * @author zhangchangsheng01@gmail.com
 */
@Slf4j
public class SftpUtil {
    private static ChannelSftp sftp = null;
    private static Session session = null;

    /**
     * 连接sftp服务器
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/17 17:08
     * @param username 用户名
     * @param password 密码
     * @param host 主机ip
     * @param port 端口号
     * @param privateKey 私钥
     * @param timeout 超时时间
     * @return com.jcraft.jsch.ChannelSftp
     */
    public static ChannelSftp sftpConnect(String username,
                                   String password,
                                   String host,
                                   int port,
                                   String privateKey,
                                   int timeout) throws Exception {

        JSch jsch = new JSch();
        if (StringUtils.isNotBlank(privateKey)) {
            // 设置私钥
            jsch.addIdentity(privateKey);
        }
        //用户名,主机,端口号
        session = jsch.getSession(username, host, port);
        //密码
        session.setPassword(password);
        session.setConfig("StrictHostKeyChecking", "no");
        // 设置timeout时间
        session.setTimeout(timeout);
        session.connect();
        Channel channel = session.openChannel("sftp");
        channel.connect();
        sftp = (ChannelSftp) channel;
        return sftp;
    }


    /**
     * 获取指定目录下的文件
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/17 17:09
     * @param directory 目录
     * @return java.util.Vector<?>
     */
    public static Vector<?> listFiles(String directory) throws SftpException {
        if (sftp == null) {
            return null;
        }
        return sftp.ls(directory);
    }



    /**
     * 获取SFTP文件内容
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/17 17:10
     * @param fileName 文件名称
     * @param ftpPath 文件路径
     * @return java.lang.String
     */
    public static String getFtpData(String fileName,String ftpPath) throws SftpException, IOException {
        try {
            if (null == sftp) {
                return null;
            }
            sftp.cd(ftpPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        InputStream in = sftp.get(fileName);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line).append("\n");
        }
        return sb.toString();
    }

    /**
     * 本地文件上传到SFTP服务器
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/25 18:53
     * @param remotePath 远程SFTP文件目录
     * @param remoteFileName 远程SFTP文件名称
     * @param localPath 本地文件目录
     * @param localFileName 本地文件名
     */
    public static void uploadFile(String remotePath, String remoteFileName, String localPath, String localFileName) {
        FileInputStream in = null;
        try {
            sftp.cd(remotePath);
            File file = new File(localPath, localFileName);
            in = new FileInputStream(file);
            sftp.put(in, remoteFileName);
        } catch (FileNotFoundException | SftpException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 写入文件
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/31 16:58
     * @param remotePath SFTP目录
     * @param remoteFileName SFTP文件名
     * @param in 输入流
     */
    public static void writeFile(String remotePath, String remoteFileName, InputStream in) {
        try {
            sftp.cd(remotePath);
            sftp.put(in, remoteFileName);
        } catch (SftpException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 文件下载
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/19 10:49
     * @param directory 源目录
     * @param downloadFile 源文件名
     * @param saveDirectory 保存到的目录
     * @param saveFile 保存的文件名
     */
    public static void download(String directory, String downloadFile, String saveDirectory, String saveFile) {
        OutputStream outputStream = null;
        try {
            if (StringUtils.isNotBlank(directory)) {
                sftp.cd(directory);
            }
            File file = new File(saveDirectory, saveFile);
            outputStream = Files.newOutputStream(file.toPath());
            sftp.get(downloadFile, outputStream);
        } catch (SftpException | IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (Objects.nonNull(outputStream)) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }




    public static void mkdir(String directory,String fileName,ChannelSftp sftp){
        try {
            sftp.cd(directory);
            sftp.mkdir(fileName);
            log.info("文件夹创建成功");
        } catch (Exception e) {
            log.error("文件夹创建失败", e);
        }
    }

    /**
     *
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/11/3 16:58
     * @param path 待删除文件或文件夹路径
     */
    public static void delete(String path){
        if (sftp == null) {
            return;
        }
        try {
            // 如果时目录,需要先遍历删除目录下的文件再删除目录
            if (sftp.stat(path).isDir()) {
                sftp.cd(path);
                Vector<ChannelSftp.LsEntry> entries = sftp.ls(".");
                for (ChannelSftp.LsEntry entry: entries) {
                    String fileName = entry.getFilename();
                    if(fileName.equals(".") || fileName.equals("..")){
                        continue;
                    }
                    delete(entry.getFilename());
                }
                sftp.cd("..");
                sftp.rmdir(path);
            } else {
                // 具体的文件路径,直接删除
                sftp.rm(path);
            }
            log.info("删除成功:{}", path);
        } catch (Exception e) {
            log.error("删除失败", e);
        }
    }

    /**
     * 关闭FTP连接
     *
     * @author zhangchangsheng01@gmail.com
     * @date 2022/10/17 17:10
     */
    public static void closeChannel() {
        if (sftp != null) {
            sftp.disconnect();
        }
        if (session != null) {
            if (session.isConnected()) {
                session.disconnect();
            }
        }
    }


}

三、单元测试

@Test
    void testConnectSFTP(){
        try {
            //创建连接
           SftpUtil.sftpConnect(username, password, host, port, null,0);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            SftpUtil.closeChannel();
        }
    }

    @Test
    void testUploadFile(){
        String localPath = "";
        try {
            //创建连接
            SftpUtil.sftpConnect(username, password, host, port, null,0);
            String fileName = "";
            SftpUtil.uploadFile(ftpPath, fileName, localPath, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            SftpUtil.closeChannel();
        }
    }

    @Test
    void testListFile() throws Exception {
        SftpUtil.sftpConnect(username, password, host, port, null, 0);
        Vector<?> vector = SftpUtil.listFiles("testDir");
        Iterator iterator = vector.iterator();
        System.out.println("文件列表:");
        while (iterator.hasNext()) {
            ChannelSftp.LsEntry file = (ChannelSftp.LsEntry) iterator.next();
            //文件名称
            System.out.println(file.getFilename());
        }
        SftpUtil.closeChannel();
    }

    @Test
    void  testCreateDirectory(){
        try {
            //创建连接
            ChannelSftp channelSftp = SftpUtil.sftpConnect(username, password, host, port, null, 0);
            SftpUtil.mkdir(ftpPath, "errorDirectory", channelSftp);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            SftpUtil.closeChannel();
        }
    }

    @Test
    void testDelete(){
        String path = new File(ftpPath, "errorDirectory").getPath();
        try {
            //创建连接
            SftpUtil.sftpConnect(username, password, host, port, null, 0);
            SftpUtil.delete(path);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            SftpUtil.closeChannel();
        }
    }