【FTP/SFTP 案例分享及主动/被动模式选择】

#博学谷IT学习技术支持#

目录

主动模式和被动模式

主动模式和被动模式区别简概述

FTPUtils案例


主动模式和被动模式

主动模式和被动模式区别简概述

        1. ① 主动模式数据传送是 "服务器"  连接到  "客户端" 端口;

            ② 被动模式数据传送是 "客户端" 连接到 "服务器" 端口。

        2. ① 主动模式需要客户端必须开放端口给服务器,大部分客户端都是在防火墙内,开放端口给FTP服务器访问比较困难;

            ② 被动模式只需要服务器端开放端口给客户端连接。

      注意点: 被动模式和主动模式的登录过程,都是FTP客户端去连接FTP服务器。

 通过上述: 如何选择FTP的连接模式,需要自身业务环境及客户需求决定

FTPUtils案例

public class FTPUtils {

    private static int timeout = 60000; //超时数
    private static final String defaultFtpEncode = "UTF-8"; //字符集
    private static String sftp = "sftp"; //sftp
    private static String ftp = "ftp"; //sftp
    private static String session = "session"; //session
    private static String ENTER_LOCAL_ACTIVE_MODE = "enterLocalActiveMode"; //主动模式


    /**
     * 传入一个通道对象
     * <p>
     * username 远程要连接的服务器的用户名
     * password 远程要连接的服务器的密码
     * ip       远程服务器ip
     * port     远程服务器的ssh服务端口
     * ChannelSftp返回指向这个通道指定的地址的channel实例
     * xException
     */
    public static HashMap<String, Object> connectSFTP(FtpSendVO ftpSendVO, ProxyConfiguration proxyConfiguration) {
        ChannelSftp channelSftp;
        //基础参数
        String password = ftpSendVO.getPassword();//密码
        String account = ftpSendVO.getAccount();//登录账户
        String ip = ftpSendVO.getHostName();//ip
        String port = ftpSendVO.getPort();//端口
        String keyFilePath = ftpSendVO.getKeyFilePath();//sshKey临时文件路径

        try {

            JSch jsch = new JSch();
            // 判断秘钥是否有秘钥
            if (keyFilePath != null) {
                // 判断是否有秘钥密码
                if (password != null && !"".equals(password)) {
                    jsch.addIdentity(keyFilePath, password);
                } else {
                    jsch.addIdentity(keyFilePath, "");
                }
            }

            Session sshSession = jsch.getSession(account, ip, Integer.parseInt(port));
            if (log.isInfoEnabled()) {
                log.info("Session created.");
            }
            // 判断是否有密码
            if (password != null) {
                sshSession.setPassword(password);
            }

            Properties sshConfig = new Properties();
           //为Session对象设置properties
            sshSession.setConfig(sshConfig);
            sshSession.setTimeout(timeout);
            sshSession.connect(); //建立SFTP通道的连接
            if (log.isInfoEnabled()) {
                log.info("Session connected.");
            }
            // 打开SFTP通道
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            if (log.isInfoEnabled()) {
                log.info("Opening Channel.");
            }
            channelSftp = (ChannelSftp) channel;
            if (log.isInfoEnabled()) {
                log.info("Connected to " + ip + ".");
            }
            HashMap<String, Object> loginInfo = new HashMap<>();
            loginInfo.put(sftp, channelSftp);
            loginInfo.put(session, sshSession);
            return loginInfo;
        } catch (Exception e) {
            log.error("SFTP连接服务器失败:", e);
            throw new xException("SFTP连接服务器失败: " + e.getMessage(), e);
        } finally {
            File file = ftpSendVO.getFile();
            if (file != null) {
                FileUtils.deleteQuietly(file);
            }
        }

    }


    public static HashMap<String, Object> connectFTP(FtpSendVO ftpSendVO, ProxyConfiguration proxyConfiguration) {

        FTPClient ftpClient;
        String password = ftpSendVO.getPassword();
        String account = ftpSendVO.getAccount();
        String ip = ftpSendVO.getHostName();
        String port = ftpSendVO.getPort();
        HashMap<String, Object> loginInfo = new HashMap<>();

        ftpClient = new FTPClient();
        try {
            
            ftpClient.connect(ip, Integer.parseInt(port));
            ftpClient.login(account, password);
            ftpClient.setType(FTPClient.TYPE_BINARY);
            ftpClient.setCharset(ftpSendVO.getServerCharset());
            System.setProperty("ftp4j.timeout", String.valueOf(timeout));

            //记录返回信息
            loginInfo.put(ftp, ftpClient);
            if (!ftpClient.isConnected()) {
                log.error("FTP服务器连接失败");
                throw new xException("FTP连接服务器失败");
            }

            return loginInfo;
        } catch (xException e) {
            log.error("FTP登录失败 message:" + e.getMessage(), e);
            throw e;
        } catch (Exception e) {
            log.error("FTP登录失败 message:" + e.getMessage(), e);
            throw new xException("FTP连接服务器失败 message:" + e.getMessage(), e);
        }

    }

    /*********************************************退出登录*********************************************************/

    /**
     * 退出FTP登录
     */
    public static Boolean ftpLoginOut(HashMap<String, Object> hashMap) {
        FTPClient ftpClient = (FTPClient) hashMap.get(ftp);

        log.info("准备关闭FTP连接:" + ftpClient);
        boolean b = false;
        if (ftpClient != null && ftpClient.isConnected()) {
            try {
                ftpClient.disconnect(true);
                b = true;
            } catch (Exception e) {
                log.error("关闭FTP连接失败 message:" + e.getMessage(), e);
                // throw new xException("关闭FTP连接失败", e);
            }
            boolean disconnectSuccess = !ftpClient.isConnected();
            if (disconnectSuccess) {
                log.info("关闭FTP连接成功");
            } else {
                log.info("关闭FTP连接失败");
            }

        }
        return b;
    }


    /**
     * sftp退出登陆
     * <p>
     * sftp对象
     * session session对象
     */
    public static Boolean sftpLoginOut(HashMap<String, Object> hashMap) {
        Boolean flag = false;
        ChannelSftp channelSftp = (ChannelSftp) hashMap.get(sftp);
        Session channelSession = (Session) hashMap.get(session);

        try {
            if (null != channelSftp && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (null != channelSession && channelSession.isConnected()) {
                channelSession.disconnect();
            }
            flag = true;
        } catch (Exception e) {
            log.error("用户退出SFTP服务器出现异常:" + e.getMessage(), e);
        }
        return flag;
    }

    /***************************************上传文件**************************************************/

    /**
     * Sftp上传文件
     *
     * @param uploadPath     上传SFTP完整路径
     * @param uploadFileList 上传文件路径]
     * @param loginInfo      认证方式(参数)
     */
    public static void uploadSftpFile(String uploadPath, List<File> uploadFileList, HashMap<String, Object> loginInfo) {
        Assert.notNull(uploadPath, "uploadPath is not null");
        Assert.notNull(uploadFileList, "uploadFileList is not null");
        //Assert.notNull(authTypeMode,"authTypeMode is not null");

        List<InputStream> inputStreamList = new ArrayList<>();
        try {

            ChannelSftp channelSftp = (ChannelSftp) loginInfo.get("sftp");

            try {
                channelSftp.cd(uploadPath);
            } catch (SftpException e) {
                log.error("SFTP器服务存放文件路径不存在,系统重新创建目录:" + uploadPath, e);
                // 目录不存在,则创建文件夹
                String[] dirs = uploadPath.split("/");
                String tempPath = "";
                int index = 0;
                mkdirDir(channelSftp, dirs, tempPath, dirs.length, index);
            }
            for (File file : uploadFileList) {
                InputStream inputStream = new FileInputStream(file);
                channelSftp.put(inputStream, file.getName());
                inputStreamList.add(inputStream);
            }
            log.info("上传文件成功!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new xException("用户上传SFTP服务器文件异常 message:" + e.getMessage(), e);
        } finally {
            if (!CollectionUtils.isEmpty(inputStreamList)) {
                try {
                    for (InputStream inputStream : inputStreamList) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                    throw new xException("用户上传SFTP关闭流异常 message:" + e.getMessage(), e);
                }
            }
            //sftpLoginOut(Objects.requireNonNull(loginInfo));
        }

    }


    public static void uploadFtpFile(String connectionType, String uploadPath, List<File> uploadFileList, HashMap<String, Object> hashMap, String serverCharset) {
        FTPClient ftpClient = null;
        //获得文件流
        try {
            //登录
            ftpClient = (FTPClient) hashMap.get(ftp);
            // 中文支持
            log.info("[FTP] serverCharset: " + serverCharset);
            ftpClient.setCharset(serverCharset);
            ftpClient.setType(FTPClient.TYPE_BINARY);
            // 用被动模式传输,解决linux服务长时间等待,导致超时问题
            if (ENTER_LOCAL_ACTIVE_MODE.equals(connectionType)) {
                ftpClient.setPassive(false);
            } else {
                ftpClient.setPassive(true);
            }

            // 设置默认超时时间
            System.setProperty("ftp4j.timeout", String.valueOf(timeout));
            try {
                try {
                    //判断目录是否存在
                    ftpClient.changeDirectory(uploadPath);
                } catch (FTPException e) {
                    log.error(e.getMessage(), e);
                    if (FTPCodes.FILE_NOT_FOUND == e.getCode()) {
                        log.error("FTP目录" + uploadPath + "不存在");
                        //判断文件是否存在
                        ftpClient.fileSize(uploadPath);
                    } else {
                        throw new FTPException(e.getCode(), e.getMessage());
                    }
                }
            } catch (FTPException e) {
                log.error(e.getMessage(), e);
                if (FTPCodes.FILE_NOT_FOUND == e.getCode()) {
                    log.error("FTP文件" + uploadPath + "不存在");
                }
            }

            //上传至Ftp
            for (File uploadFile : uploadFileList) {
                ftpClient.upload(uploadFile);
                log.info("文件发送成功:" + uploadFile.getName());
            }

        } catch (Exception e) {
            log.error("ftp文件上传失败" + e.getMessage(), e);
            throw new xException("上传ftp失败 message:" + e.getMessage(), e);
        } finally {
            //关闭连接
//            ftpLoginOut(Objects.requireNonNull(hashMap));
        }
    }

    /**
     * ftp上传文件
     *
     * @param connectionType
     * @param uploadPath     文件存入FTP 的路径
     * @return 成功返回true   失败返回false
     * @throws SocketException
     * @throws IOException
     */
    public static void uploadFtpFile(String connectionType, String uploadPath, List<File> uploadFileList, HashMap<String, Object> hashMap) {
        log.info("默认FTP上传方法: defaultFtpEncode");
        uploadFtpFile(connectionType, uploadPath, uploadFileList, hashMap, defaultFtpEncode);
    }


    /******************************************** 删除文件 *****************************************************/
    /**
     * 删除FTP
     *
     * @param ftpName    ftp上的文件名
     * @param uploadPath ftp上的文件路径
     * @return 成功返回true   失败返回false
     * @throws SocketException
     * @throws IOException
     */
    public static Boolean deleteFtpFile(String uploadPath, String ftpName, HashMap<String, Object> hashMap) {
        Boolean flag;
        FTPClient ftpClient;
        //保存至Ftp
        try {
            ftpClient = (FTPClient) hashMap.get(ftp);
            System.setProperty("ftp4j.timeout", String.valueOf(timeout));
            ftpClient.deleteFile(ftpName);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new xException("删除ftp失败 message:" + e.getMessage(), e);
        } finally {
            //关闭连接
            ftpLoginOut(Objects.requireNonNull(hashMap));
        }
        return true;
    }


    /**
     * 删除sftp文件
     *
     * @param directory  要删除文件所在目录
     * @param deleteFile 要删除的文件 /x/xx/xx/myfile.txt
     * @throws Exception
     */
    public static Boolean deleteSftpFile(String directory, String deleteFile, HashMap<String, Object> hashMap) {
        Boolean flag = true;
        try {
            ChannelSftp channelSftp = (ChannelSftp) hashMap.get(sftp);
            channelSftp.cd(directory);
            channelSftp.rm(deleteFile);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new xException("删除sftp失败 message:" + e.getMessage(), e);
        } finally {
            //关闭连接
            sftpLoginOut(Objects.requireNonNull(hashMap));
        }
        return flag;
    }


    /**********************************************下载文件**************************************************************/
    /**
     * 下载FTP
     *
     * @param ftpName   ftp上的文件名
     * @param localFile 保存的本地地址
     * @param path      ftp上的文件路径
     * @return 成功返回true   失败返回false
     * @throws SocketException
     * @throws IOException
     */
    public static String FTPDownloadFile(String path, String ftpName, File localFile, FtpSendVO ftpSendVO) {
        boolean flag = true;
        //保存至Ftp
        FTPClient ftpClient = new FTPClient();// ftpHost为FTP服务器的IP地址,port为FTP服务器的登陆端口,ftpHost为String型,port为int型。
        try {
            connectFTP(ftpSendVO, null);
            ftpClient.download(ftpName, localFile);
            log.info("FTP文件名——{}", ftpName);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return "SocketNotSuccess";
        } finally {
            //关闭连接
            try {
                ftpClient.disconnect(true);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        return "SUCCESS";
    }


    /**
     * 下载文件
     *
     * @param downloadFilePath 要下载的文件所在绝对路径
     * @param downloadFileName 要下载的文件名(sftp服务器上的文件名)
     * @param loginInfo        用户认证方式
     */
    public static void SFTPDownload(String downloadFilePath, String downloadFileName, String saveFile, HashMap<String, Object> loginInfo) throws Exception {
        Assert.notNull(downloadFilePath, "downloadFilePath is not null");
        Assert.notNull(downloadFileName, "downloadFileName is not null");
        Assert.notNull(saveFile, "saveFile is not null");
        Assert.notNull(loginInfo, "loginInfo is not null");


        OutputStream outputStream = null;
        ChannelSftp sftp;
        try {
            sftp = (ChannelSftp) loginInfo.get("sftp");

    
            sftp.cd(downloadFilePath);
            sftp.ls(downloadFileName);
            outputStream = new FileOutputStream(saveFile);
            sftp.get(downloadFileName, outputStream);
            log.info("文件下载完成!");

        } finally {
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            sftpLoginOut(loginInfo);
        }
    }


    /****************************** 获取文件的大小 *****************************************/
    /**
     * ftp获取文件的大小
     *
     * @param hashMap
     * @return
     */
    public static FileMateData ftpFolderSize(String directoryPath, String fileName, HashMap<String, Object> hashMap) {

        if (StringUtils.isEmpty(fileName)) {
            throw new xException("文件名不能为空");
        }
        FileMateData fileMateData = new FileMateData();
        try {
            FTPClient client = (FTPClient) hashMap.get(ftp);
            //查看当前目录
            String workingDirectory = client.currentDirectory();
            log.info("当前目录: {}", workingDirectory);
            //获取指定目录下的文件及目录
            fileMateData.setSize(client.fileSize(directoryPath) / 1000 + "KB");
            fileMateData.setFileName(fileName);

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return fileMateData;
    }


    public static FileMateData sftpFolderSize(String directoryPath, String fileName, HashMap<String, Object> hashMap) {
        ChannelSftp channelSftp = (ChannelSftp) hashMap.get(sftp);
        long size = 0L;
        FileMateData fileMateData = new FileMateData();
        try {
            Vector list = channelSftp.ls(directoryPath);
            if (list.isEmpty()) {
                throw new xException(fileName + " 文件不存在");
            }
            for (Object sftpFile : list) {
                ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) sftpFile;
                String nextName = lsEntry.getFilename();
                if (nextName.equals(fileName)) {
                    SftpATTRS attrs = lsEntry.getAttrs();
                    size = attrs.getSize();
                    fileMateData.setSize(size / 1000 + "KB");
                    fileMateData.setFileName(fileName);
                }
            }

        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new xException(fileName + " 文件异常: " + ex.getMessage(), ex);
        }
        return fileMateData;
    }


    /*******************************************临时文件生成方法*******************************************/

    /**
     * 生成文件
     *
     * @param fileName
     * @param sshKey
     * @param temporaryPath 临时文件保存路径
     * @return
     */
    public static File createFile(String fileName, String sshKey, String temporaryPath) {
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        //String extFile = sdf.format(new Date()) + UUID.randomUUID().toString().replace("-", "");
        return writerFile(fileName, sshKey, temporaryPath);
    }

    /**
     * 创建文件
     */
    public static File writerFile(String fileName, String sshKey, String temporaryPath) {
        File file = null;
        // 生成格式文件
        Writer write = null;
        try {
            file = new File(temporaryPath);
            if (!file.exists()) {
                file.mkdir();
            }
            // 保证创建一个新文件
            file = new File(temporaryPath + fileName);
            log.info("filename: " + file.getAbsolutePath());
            // 如果已存在,删除旧文件
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            // 将格式化后的字符串写入文件

            write = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
            write.write(sshKey);
            write.flush();

        } catch (Exception e) {
            log.error("生成文件异常: " + e.getMessage(), e);
        } finally {
            if (write != null) {
                try {
                    write.close();

                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        // 返回文件对象
        return file;
    }

    /**
     * 递归根据路径创建文件夹
     *
     * @param dirs     根据 / 分隔后的数组文件夹名称
     * @param tempPath 拼接路径
     * @param length   文件夹的格式
     * @param index    数组下标
     * @return
     */
    public static void mkdirDir(ChannelSftp channelSftp, String[] dirs, String tempPath, int length, int index) {
        // 以"/a/b/c/d"为例按"/"分隔后,第0位是"";顾下标从1开始
        index++;
        if (index < length) {
            // 目录不存在,则创建文件夹
            tempPath += "/" + dirs[index];
        }
        try {
            log.info("检测目录[" + tempPath + "]");
            channelSftp.cd(tempPath);

            if (index < length) {
                mkdirDir(channelSftp, dirs, tempPath, length, index);
            }
        } catch (SftpException ex) {
            log.error("创建目录[" + tempPath + "失败" + ex.getMessage(), ex);
            try {
                channelSftp.mkdir(tempPath);
                channelSftp.cd(tempPath);
            } catch (SftpException e) {
                log.error("创建目录[" + tempPath + "]失败,异常信息[" + e.getMessage() + "]", e);
                throw new RuntimeException("创建目录[" + tempPath + "]失败,异常信息[" + e.getMessage() + "]", e);
            }
            log.info("进入目录[" + tempPath + "]");
            mkdirDir(channelSftp, dirs, tempPath, length, index);
        }
    }
}
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值