• sftp上传下载


    最近在做sftp的上传下载,查询了相关资料,最终选定jsch

    jsch的官网看起来有点不舒服,这里就不记了

    maven的pom引入,jsch最新版本 0.1.54

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

    主要包括几个部分:

    1、获取sftp通道--ChannelSftp

    主要有登录sftp的服务器信息,用户名密码等。然后获取sftp通道并返回。

    /**
         * 密码方式登录sftp服务器并获取连接
         *
         * @param host     sftp服务器地址
         * @param port     端口,默认22
         * @param user     sftp服务器登录用户
         * @param password sftp登录用户密码
         * @return
         * @throws JSchException
         */
        public static ChannelSftp getChannelSftp(String host, int port, String user, String password) throws JSchException {
            logger.debug("密码方式登录sftp服务器{},端口{}", host, port);
            JSch jSch = new JSch();
            Session session = jSch.getSession(user, host, port);
            session.setPassword(password);
            //设置首次登录是否需要检查
            session.setConfig("StrictHostKeyChecking", "no");
            //设置连接超时时间 -- 不设置会报session is down的错,暂未查到原因
            session.connect(30000);
            //获取sftp服务器连接
            Channel channel = session.openChannel("sftp");
            channel.connect();
            //返回sftp连接
            return (ChannelSftp) channel;
        }

    2、文件下载

    jsch提供了一系列的get方法,用于文件下载

    /**
         * 从sftp服务器下载当前目录下的所有文件和目录,不在本地创建当前remotePath根目录
         *
         * @param sftp       sftp服务器连接
         * @param remotePath 当前要下载的sftp远程服务器目录
         * @param localPath  当前要下载的文件本地目录
         * @param exceptList 不需要下载的集合--文件名或文件夹名
         * @throws SftpException
         */
        public static void downloadFile(ChannelSftp sftp, String remotePath, String localPath, List<String> exceptList) throws SftpException {
            //获取当前远程目录的所有文件  --  该目录必须存在,否则会抛异常
            Vector vector = sftp.ls(remotePath);
            logger.debug("下载文件路径{},文件/文件夹总数{}", remotePath, vector.size());
            for (Object object : vector) {
                if (object instanceof ChannelSftp.LsEntry) {
                    ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) object;
                    String filename = lsEntry.getFilename();
                    SftpATTRS attrs = lsEntry.getAttrs();
                    //只操作不在exceptList列表中的数据
                    if (CollectionUtils.isEmpty(exceptList) || !exceptList.contains(filename)) {
                        if (attrs.isDir()) {
                            if (filename.length() == 0) {
                                continue;
                            }
                            String sub = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
                            if (StringUtils.isBlank(sub)) {
                                logger.info("异常数据" + filename);
                                continue;
                            }
                            //如果当前操作对象为文件夹,则直接在本地创建相应的目录,并递归获取该目录下的文件
                            File file = new File(localPath + "/" + filename);
                            file.mkdir();
                            downloadFile(sftp, remotePath + "/" + filename, localPath + "/" + filename, exceptList);
                        } else {
                            //如果当前操作对象为文件夹,切换到当前服务器目录,并下载该文件到本地
                            sftp.cd(remotePath);
                            logger.debug("下载文件{}到{}", filename, localPath);
                            sftp.get(filename, localPath);
                        }
                    }
                }
            }
        }

    3、文件上传  -- 这里实现上传目录而非单个文件

    jsch提供了一系列的put方法用于文件上传

    /**
         * 上传整个目录文件到sftp服务器,会创建当前localPath根目录
         *
         * @param sftp       sftp连接
         * @param remotePath 当前要上传的远程目标目录
         * @param localPath  当前上传的本地文件目录
         * @throws SftpException
         */
        public static void uploadFile(ChannelSftp sftp, String remotePath, String localPath) throws SftpException {
            //获取当前操作的文件对象
            File rootFile = new File(localPath);
            String rootName = rootFile.getName();
    
            //切换到服务器当前目录  -- 该目录必须存在,否则会抛异常
            sftp.cd(remotePath);
            if (rootFile.isFile()) {
                //当前操作对象是文件,则上传文件到服务器
                sftp.put(rootName);
            } else {
                try {
                    //切换到当前文件夹目录,不存在则异常
                    sftp.cd(rootName);
                } catch (SftpException e) {
                    //不存在,进入异常,创建目录
                    sftp.mkdir(rootName);
                }
                //获取当前目录下的所有文件
                File[] files = rootFile.listFiles();
                for (File file : files) {
                    if (file.isFile()) {
                        //当前操作对象是文件,则上传文件到服务器
                        sftp.put(localPath + "/" + file.getName(), remotePath + "/" + rootName);
                    } else {
                        //如果当前操作对象是文件夹,则递归上传目录下的文件
                        uploadFile(sftp, remotePath + "/" + rootName, localPath + "/" + file.getName());
                    }
                }
            }
        }

    4、移动文件--这里实现整个目录的移动,根目录文件夹不删除。

    jsch本身没有移动文件的方法,但提供了rename方法,可以将目标文件rename重命名到新的目录,以实现文件的移动--单个文件操作

    /**
         * 重命名/移动文件到指定目录
         *
         * @param sftp     sftp连接
         * @param rootPath 当前操作目录 -- 作为透传根目录 不可删除
         * @param srcPath  文件夹源目录--绝对路径  源目录必须存在
         * @param dstPath  文件夹移动目标目录--绝对路径 最多允许一层不存在的目录
         * @throws SftpException
         */
        public static void renameFile(ChannelSftp sftp, String rootPath, String srcPath, String dstPath) throws SftpException {
            Vector vector = sftp.ls(srcPath);
            if (CollectionUtils.isEmpty(vector) && !rootPath.equals(srcPath)) {
                logger.info("源文件夹里没有文件");
                //删除空文件夹
                sftp.rmdir(srcPath);
                return;
            }
    
            try {
                //判断目标目录是否存在
                sftp.ls(dstPath);
            } catch (SftpException e) {
                //创建目标目录
                sftp.mkdir(dstPath);
            }
    
            for (Object object : vector) {
                if (object instanceof ChannelSftp.LsEntry) {
                    ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) object;
                    String filename = lsEntry.getFilename();
                    SftpATTRS attrs = lsEntry.getAttrs();
                    if (attrs.isDir()) {
                        if (filename.length() == 0) {
                            continue;
                        }
                        String sub = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
                        if (StringUtils.isBlank(sub)) {
                            logger.info("异常数据" + filename);
                            continue;
                        }
                        //正常文件夹是否存在
                        renameFile(sftp, rootPath, srcPath + SEPARATOR + filename, dstPath + SEPARATOR + filename);
                    } else {
                        //如果是文件,则直接移动
                        sftp.rename(srcPath + SEPARATOR + filename, dstPath + SEPARATOR + filename);
                    }
                }
            }
            //移动完成后,删除空目录
            if (CollectionUtils.isEmpty(sftp.ls(srcPath)) && !rootPath.equals(srcPath)) {
                sftp.rmdir(srcPath);
            }
    
        }

    5、关闭sftp通道

    /**
         * 断开sftp相关连接
         *
         * @param sftp
         * @throws JSchException
         */
        public static void closeSftp(ChannelSftp sftp) throws JSchException {
            if (sftp != null) {
                if (sftp.isConnected()) {
                    sftp.disconnect();
                }
                Session session = sftp.getSession();
                if (session != null) {
                    if (session.isConnected()) {
                        session.disconnect();
                    }
                }
            }
    
        }

    完整源码

    import com.j1cn.commons.utils.StringUtils;
    import com.jcraft.jsch.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.util.CollectionUtils;
    
    import java.io.File;
    import java.util.List;
    import java.util.Vector;
    
    /**
     * sftp服务器操作工具类
     *
     * @author flysand
     **/
    public class SftpUtils {
    
        private static final Logger logger = LoggerFactory.getLogger(SftpUtils.class);
    
        public static final String SEPARATOR = "/";
    
        public static final String RIGHT_SEPARATOR = "\";
    
        /**
         * 密码方式登录sftp服务器并获取连接
         *
         * @param host     sftp服务器地址
         * @param port     端口,默认22
         * @param user     sftp服务器登录用户
         * @param password sftp登录用户密码
         * @return
         * @throws JSchException
         */
        public static ChannelSftp getChannelSftp(String host, int port, String user, String password) throws JSchException {
            logger.debug("密码方式登录sftp服务器{},端口{}", host, port);
            JSch jSch = new JSch();
            Session session = jSch.getSession(user, host, port);
            session.setPassword(password);
            //设置首次登录是否需要检查
            session.setConfig("StrictHostKeyChecking", "no");
            //设置连接超时时间 -- 不设置会报session is down的错,暂未查到原因
            session.connect(30000);
            //获取sftp服务器连接
            Channel channel = session.openChannel("sftp");
            channel.connect();
            //返回sftp连接
            return (ChannelSftp) channel;
        }
    
        /**
         * 断开sftp相关连接
         *
         * @param sftp
         * @throws JSchException
         */
        public static void closeSftp(ChannelSftp sftp) throws JSchException {
            if (sftp != null) {
                if (sftp.isConnected()) {
                    sftp.disconnect();
                }
                Session session = sftp.getSession();
                if (session != null) {
                    if (session.isConnected()) {
                        session.disconnect();
                    }
                }
            }
    
        }
    
    
        /**
         * 从sftp服务器下载当前目录下的所有文件和目录,不在本地创建当前remotePath根目录
         *
         * @param sftp       sftp服务器连接
         * @param remotePath 当前要下载的sftp远程服务器目录
         * @param localPath  当前要下载的文件本地目录
         * @param exceptList 不需要下载的集合--文件名或文件夹名
         * @throws SftpException
         */
        public static void downloadFile(ChannelSftp sftp, String remotePath, String localPath, List<String> exceptList) throws SftpException {
            //获取当前远程目录的所有文件  --  该目录必须存在,否则会抛异常
            Vector vector = sftp.ls(remotePath);
            logger.debug("下载文件路径{},文件/文件夹总数{}", remotePath, vector.size());
            for (Object object : vector) {
                if (object instanceof ChannelSftp.LsEntry) {
                    ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) object;
                    String filename = lsEntry.getFilename();
                    SftpATTRS attrs = lsEntry.getAttrs();
                    //只操作不在exceptList列表中的数据
                    if (CollectionUtils.isEmpty(exceptList) || !exceptList.contains(filename)) {
                        if (attrs.isDir()) {
                            if (filename.length() == 0) {
                                continue;
                            }
                            String sub = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
                            if (StringUtils.isBlank(sub)) {
                                logger.info("异常数据" + filename);
                                continue;
                            }
                            //如果当前操作对象为文件夹,则直接在本地创建相应的目录,并递归获取该目录下的文件
                            File file = new File(localPath + "/" + filename);
                            file.mkdir();
                            downloadFile(sftp, remotePath + "/" + filename, localPath + "/" + filename, exceptList);
                        } else {
                            //如果当前操作对象为文件夹,切换到当前服务器目录,并下载该文件到本地
                            sftp.cd(remotePath);
                            logger.debug("下载文件{}到{}", filename, localPath);
                            sftp.get(filename, localPath);
                        }
                    }
                }
            }
        }
    
        /**
         * 上传整个目录文件到sftp服务器,会创建当前localPath根目录
         *
         * @param sftp       sftp连接
         * @param remotePath 当前要上传的远程目标目录
         * @param localPath  当前上传的本地文件目录
         * @throws SftpException
         */
        public static void uploadFile(ChannelSftp sftp, String remotePath, String localPath) throws SftpException {
            //获取当前操作的文件对象
            File rootFile = new File(localPath);
            String rootName = rootFile.getName();
    
            //切换到服务器当前目录  -- 该目录必须存在,否则会抛异常
            sftp.cd(remotePath);
            if (rootFile.isFile()) {
                //当前操作对象是文件,则上传文件到服务器
                sftp.put(rootName);
            } else {
                try {
                    //切换到当前文件夹目录,不存在则异常
                    sftp.cd(rootName);
                } catch (SftpException e) {
                    //不存在,进入异常,创建目录
                    sftp.mkdir(rootName);
                }
                //获取当前目录下的所有文件
                File[] files = rootFile.listFiles();
                for (File file : files) {
                    if (file.isFile()) {
                        //当前操作对象是文件,则上传文件到服务器
                        sftp.put(localPath + "/" + file.getName(), remotePath + "/" + rootName);
                    } else {
                        //如果当前操作对象是文件夹,则递归上传目录下的文件
                        uploadFile(sftp, remotePath + "/" + rootName, localPath + "/" + file.getName());
                    }
                }
            }
        }
    
        /**
         * 重命名/移动文件到指定目录
         *
         * @param sftp     sftp连接
         * @param rootPath 当前操作目录 -- 作为透传根目录 不可删除
         * @param srcPath  文件夹源目录--绝对路径  源目录必须存在
         * @param dstPath  文件夹移动目标目录--绝对路径 最多允许一层不存在的目录
         * @throws SftpException
         */
        public static void renameFile(ChannelSftp sftp, String rootPath, String srcPath, String dstPath) throws SftpException {
            Vector vector = sftp.ls(srcPath);
            if (CollectionUtils.isEmpty(vector) && !rootPath.equals(srcPath)) {
                logger.info("源文件夹里没有文件");
                //删除空文件夹
                sftp.rmdir(srcPath);
                return;
            }
    
            try {
                //判断目标目录是否存在
                sftp.ls(dstPath);
            } catch (SftpException e) {
                //创建目标目录
                sftp.mkdir(dstPath);
            }
    
            for (Object object : vector) {
                if (object instanceof ChannelSftp.LsEntry) {
                    ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) object;
                    String filename = lsEntry.getFilename();
                    SftpATTRS attrs = lsEntry.getAttrs();
                    if (attrs.isDir()) {
                        if (filename.length() == 0) {
                            continue;
                        }
                        String sub = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
                        if (StringUtils.isBlank(sub)) {
                            logger.info("异常数据" + filename);
                            continue;
                        }
                        //正常文件夹是否存在
                        renameFile(sftp, rootPath, srcPath + SEPARATOR + filename, dstPath + SEPARATOR + filename);
                    } else {
                        //如果是文件,则直接移动
                        sftp.rename(srcPath + SEPARATOR + filename, dstPath + SEPARATOR + filename);
                    }
                }
            }
            //移动完成后,删除空目录
            if (CollectionUtils.isEmpty(sftp.ls(srcPath)) && !rootPath.equals(srcPath)) {
                sftp.rmdir(srcPath);
            }
    
        }
    }
  • 相关阅读:
    C#生成指定范围内的不重复随机数
    jquery移除元素某个属性
    让html里的js脚本延迟5秒运行
    jquery刷新局部和全页的方法
    jquery旋转插件rotate参数说明
    按照日期生成编号
    ajax请求成功后如何调用bootstrap modal?
    WPF MVVM模式不用Prism
    C#去掉字符串两端空格以及去掉字符串中多余空格保留一个空格
    依赖项属性
  • 原文地址:https://www.cnblogs.com/flysand/p/7985725.html
Copyright © 2020-2023  润新知