SpringBoot入门系列(八)——集成FTP_springboot集成ftp-程序员宅基地

技术标签: java  sftp  springboot  

开发中经常需要从客户或者本公司的FTP服务器上下载、同步数据,那么FTP相关的知识就是必不可少的。
一般来说springboot使用ftp有两种,一是ftpClient,一种是sftp。由于ftpClient相比于sftp工具较为落后,对ssh支持度不高,故此选取sftp
一、pom

<!-- sftp -->
		<dependency>
			<groupId>jsch</groupId>
			<artifactId>jsch</artifactId>
			<version>0.1.51</version>
		</dependency>

二、配置
其实没有什么特别复杂的配置,使用的时候登陆就好,工具类如下:

package usi.dbdp.getTeleComConfigFile.util;
import com.jcraft.jsch.*;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
 
import java.io.*;
import java.util.Vector;
 
/**
 * FTP服务器工具类:
 *      JSch类 通过 SFTP 协议上传文件到 freeSSHd 服务器
 *
 * @author  xu
 * @date	2020-7-16
 */
public class SftpUtil {
    
 
    private Logger logger = LogManager.getLogger(SftpUtil.class);
 
    private ChannelSftp sftp;
 
    private Session session;
 
    /**
     * 用户名
     */
    private String username;
 
    /**
     * 密码
     */
    private String password;
 
    /**
     * 秘钥
     */
    private String privateKey;
 
    /**
     * FTP服务器Ip
     */
    private String host;
 
    /**
     * FTP服务器端口号
     */
    private int port;
 
    /**
     * 构造器:基于密码认证sftp对象
     * @param username  用户名
     * @param password  密码
     * @param host      服务器ip
     * @param port      服务器端口号
     */
    public SftpUtil(String username, String password, String host, int port){
    
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
    }
 
    /**
     * 连接SFTP服务器
     */
    public void login(){
    
        JSch jsch = new JSch();
        try{
    
            if(privateKey != null){
    
                //设置登陆主机的秘钥
                jsch.addIdentity(privateKey);
            }
            //采用指定的端口连接服务器
            session = jsch.getSession(username,host,port);
            if(password != null){
    
                //设置登陆主机的密码
                session.setPassword(password);
            }
            //优先使用 password 验证   注:session.connect()性能低,使用password验证可跳过gssapi认证,提升连接服务器速度
            session.setConfig("PreferredAuthentications","password");
            //设置第一次登陆的时候提示,可选值:(ask | yes | no)
            session.setConfig("StrictHostKeyChecking","no");
            session.connect();
            //创建sftp通信通道
            Channel channel = session.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
            logger.info("sftp server connect success !!");
        }catch (JSchException e){
    
            logger.error("SFTP服务器连接异常!!", e);
        }
    }
 
    /**
     * 关闭SFTP连接
     */
    public void logout(){
    
        if(sftp != null){
    
            if(sftp.isConnected()){
    
                sftp.disconnect();
                logger.info("sftp is close already");
            }
        }
        if(session != null){
    
            if(session.isConnected()){
    
                session.disconnect();
                logger.info("session is close already");
            }
        }
    }
 
    /**
     * 将输入流上传到SFTP服务器,作为文件
     *
     * @param directory     上传到SFTP服务器的路径
     * @param sftpFileName  上传到SFTP服务器后的文件名
     * @param input         输入流
     * @throws SftpException
     */
    public void upload(String directory, String sftpFileName, InputStream input) throws SftpException{
    
        long start = System.currentTimeMillis();
        try{
    
            //如果文件夹不存在,则创建文件夹
            if(sftp.ls(directory) == null){
    
                sftp.mkdir(directory);
            }
            //切换到指定文件夹
            sftp.cd(directory);
        }catch (SftpException e){
    
            //创建不存在的文件夹,并切换到文件夹
            sftp.mkdir(directory);
            sftp.cd(directory);
        }
        sftp.put(input, sftpFileName);
        logger.info("文件上传成功!! 耗时:{}ms",(System.currentTimeMillis() - start));
    }
 
    /**
     * 上传单个文件
     *
     * @param directory     上传到SFTP服务器的路径
     * @param uploadFileUrl 文件路径
     */
    public void upload(String directory, String uploadFileUrl){
    
        File file = new File(uploadFileUrl);
        try{
    
            upload(directory, file.getName(), new FileInputStream(file));
        }catch (FileNotFoundException | SftpException e){
    
            logger.error("上传文件异常!", e);
        }
    }
 
    /**
     * 将byte[] 上传到SFTP服务器,作为文件
     *           注: 从String转换成byte[] 需要指定字符集
     *
     * @param directory     上传到SFTP服务器的路径
     * @param sftpFileName  上传SFTP服务器后的文件名
     * @param bytes         字节数组
     */
    public void upload(String directory, String sftpFileName, byte[] bytes){
    
        try{
    
            upload(directory, sftpFileName, new ByteArrayInputStream(bytes));
        }catch (SftpException e){
    
            logger.error("上传文件异常!", e);
        }
    }
 
    /**
     * 将字符串按照指定编码格式上传到SFTP服务器
     *
     * @param directory       上传到SFTP服务器的路径
     * @param sftpFileName    上传SFTP服务器后的文件名
     * @param dataStr         字符串
     * @param charsetName     字符串的编码格式
     */
    public void upload(String directory, String sftpFileName, String dataStr, String charsetName){
    
        try{
    
            upload(directory, sftpFileName, new ByteArrayInputStream(dataStr.getBytes(charsetName)));
        }catch (UnsupportedEncodingException | SftpException e){
    
            logger.error("上传文件异常!", e);
        }
    }
 
    /**
     * 下载文件
     *
     * @param directory     SFTP服务器的文件路径
     * @param downloadFile  SFTP服务器上的文件名
     * @param saveFile      保存到本地路径
     */
    public void download(String directory, String downloadFile, String saveFile){
    
        try{
    
            if(directory != null && !"".equals(directory)){
    
                sftp.cd(directory);
            }
            File file = new File(saveFile);
            sftp.get(downloadFile, new FileOutputStream(file));
        }catch (SftpException | FileNotFoundException e){
    
            logger.error("文件下载异常!", e);
        }
    }
 
    /**
     * 下载文件
     *
     * @param directory     SFTP服务器的文件路径
     * @param downloadFile  SFTP服务器上的文件名
     * @return              字节数组
     */
    public byte[] download(String directory, String downloadFile){
    
        try{
    
            if(directory != null && !"".equals(directory)){
    
                sftp.cd(directory);
            }
            InputStream inputStream = sftp.get(downloadFile);
            return IOUtils.toByteArray(inputStream);
        }catch (SftpException | IOException e){
    
            logger.error("---------------------------文件下载异常!---------------------------", e);
        }
        return null;
    }
 
    /**
     * 下载文件
     *
     * @param directory     SFTP服务器的文件路径
     * @param downloadFile  SFTP服务器上的文件名
     * @return              输入流
     */
    public InputStream downloadStream(String directory, String downloadFile){
    
        try{
    
            if(directory != null && !"".equals(directory)){
    
                sftp.cd(directory);
            }
            return sftp.get(downloadFile);
        }catch (SftpException e){
    
            logger.error("文件下载异常!", e);
        }
        return null;
    }
 
    /**
     * 删除文件
     *
     * @param directory         SFTP服务器的文件路径
     * @param deleteFileName    删除的文件名称
     */
    public void delete(String directory, String deleteFileName){
    
        try{
    
            sftp.cd(directory);
            sftp.rm(deleteFileName);
        }catch (SftpException e){
    
            logger.error("文件删除异常!", e);
        }
    }
 
    /**
     * 删除文件夹
     *
     * @param directory         SFTP服务器的文件路径
     */
    public void delete(String directory){
    
        Vector vector = listFiles(directory);
        vector.remove(0);
        vector.remove(0);
        for(Object v : vector){
    
            ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry)v;
            try{
    
                sftp.cd(directory);
                sftp.rm(lsEntry.getFilename());
            }catch (SftpException e){
    
                logger.error("文件删除异常!", e);
            }
        }
    }
 
    /**
     * 获取文件夹下的文件
     *
     * @param directory     路径
     * @return
     */
    public Vector<?> listFiles(String directory){
    
        try{
    
            if(isDirExist(directory)){
    
                Vector<?> vector =  sftp.ls(directory);
                //移除上级目录和根目录:"." ".."
                vector.remove(0);
                vector.remove(0);
                return vector;
            }
        }catch (SftpException e){
    
            logger.error("获取文件夹信息异常!", e);
        }
        return null;
    }
 
    /**
     * 检测文件夹是否存在
     *
     * @param directory     路径
     * @return
     */
    public boolean booleanUrl(String directory){
    
        try{
    
            if(sftp.ls(directory) == null){
    
                return false;
            }
        }catch (Exception e){
    
            logger.error("---------------------检测文件夹异常!--------------------", e);
        }
        return true;
    }
 
    /**
     * 创建一个文件目录
     *
     * @param createpath        路径
     * @return
     */
    public boolean createDir(String createpath) {
    
        try {
    
            if (isDirExist(createpath)) {
    
                this.sftp.cd(createpath);
                return true;
            }
            String pathArry[] = createpath.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArry) {
    
                if (path.equals("")) {
    
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString())) {
    
                    sftp.cd(filePath.toString());
                } else {
    
                    // 建立目录
                    sftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }
            }
            this.sftp.cd(createpath);
        } catch (SftpException e) {
    
            logger.error("目录创建异常!", e);
            return false;
        }
        return true;
    }
 
    /**
     * 判断目录是否存在
     * @param directory     路径
     * @return
     */
    public boolean isDirExist(String directory) {
    
        boolean isDirExistFlag = false;
        try {
    
            SftpATTRS sftpATTRS = this.sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
    
            if (e.getMessage().toLowerCase().equals("no such file")) {
    
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }
    
    /**
	 * 方法功能说明:目录不存在时创建目录  
	 * @参数: @param path      
	 * @return void     
	 * @throws
	 */
    public void mkdirs(String path){
    
		File file = new File(path);
		String fs = file.getParent();
		file = new File(fs);
		if(!file.exists()){
    
			file.mkdirs();
		}
	}
    /**
    * 判断文件或目录是否存在
    * @param directory     路径
    * @return
    */
    public boolean isExist(String path,ChannelSftp sftp){
    
        boolean  isExist=false;
        try {
    
            sftp.lstat(path);
            isExist = true;
        } catch (Exception e) {
    
            if (e.getMessage().toLowerCase().equals("no such file")) {
    
                isExist = false;
            }
        }
        return isExist;
    }
}

三、具体使用

public String readFile(String remoteFileName,String remoteDir) {
    
		SftpUtil sftpUtil = new SftpUtil(username, password, host, port);
		sftpUtil.login();
		String res = new String(sftpUtil.download(remoteDir, remoteFileName));;
		if(StringUtils.isEmpty(res)) {
    
			logger.info("----------------trying download again---------------");
		}
		if(StringUtils.isEmpty(res)) {
    
			logger.error("--------------response file is null---------------");
		}
		return StringUtils.isEmpty(res)?null:res;
	}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39203889/article/details/107489833

智能推荐

华三SDN产业链分析-程序员宅基地

文章浏览阅读218次。为什么80%的码农都做不了架构师?>>> ..._h3c virtual converged framework切片

手把手教你开发第一个HarmonyOS (鸿蒙)移动应用_鸿蒙移动应用开发-程序员宅基地

文章浏览阅读1.9w次,点赞44次,收藏268次。AndroidIOSHarmonyOS (鸿蒙)文档概览-HarmonyOS应用开发官网2.1.1 系统的定位搭载该操作系统的设备在系统层⾯融为⼀体、形成超级终端,让设备的硬件能⼒可以弹性 扩展,实现设备之间 硬件互助,资源共享。对消费者⽽⾔,HarmonyOS能够将⽣活场景中的各类终端进⾏能⼒整合,实现不同终端 设备之间的快速连接、能⼒互助、资源共享,匹配合适的设备、提供流畅的全场景体验。⾯向开发者,实现⼀次开发,多端部署。_鸿蒙移动应用开发

AndroidStudio无代码高亮解决办法_android studio 高亮-程序员宅基地

文章浏览阅读2.8k次。AndroidStudio 升级到 4.2.2 版本后,没有代码高亮了,很蛋疼。解决办法是:点开上方的 File,先勾选 Power Save Mode 再取消就可以了。_android studio 高亮

swift4.0 valueForUndefinedKey:]: this class is not key value coding-compliant for the key unity.'_forundefinedkey swift4-程序员宅基地

文章浏览阅读1k次。使用swift4.0整合Unity出现[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key unity.'在对应属性前加@objc 即可。或者调回swift3.2版本_forundefinedkey swift4

Spring Security2的COOKIE的保存时间设置_springsecurity 设置cookie失效时间-程序员宅基地

文章浏览阅读1.3k次。http auto-config="true" access-denied-page="/common/403.htm"> intercept-url pattern="/login.**" access="IS_AUTHENTICATED_ANONYMOUSLY"/> form-login login-page="/login.jsp" defau_springsecurity 设置cookie失效时间

view滑动冲突解决实战篇2(外部拦截法)_viewpage2外部拦截事件-程序员宅基地

文章浏览阅读1.1k次。继上篇内部拦截法需求还是跟上篇一样。只不过这次用外部拦截法来解决;只要在父容器添加如下代码就可以解决了滑动冲突,很简单,套模板就行 // 分别记录上次滑动的坐标(onInterceptTouchEvent) private int mLastXIntercept = 0; private int mLastYIntercept = 0; @Override public bo_viewpage2外部拦截事件

随便推点

Kotlin相关面试题_kotlin面试题-程序员宅基地

文章浏览阅读1.9w次,点赞26次,收藏185次。目录一.请简述下什么是kotlin?它有什么特性?二.Kotlin 中注解 @JvmOverloads 的作用?三.Kotlin中的MutableList与List有什么区别?四.kotlin实现单例的几种方式?五. kotlin中关键字data的理解?相对于普通的类有哪些特点?六.什么是委托属性?简单说一下应用场景?七.kotlin中with、run、apply、let函数的区别?一般用于什么场景?八.kotlin中Unit的应用以及和Java中void的区别?九.Ko_kotlin面试题

HEVC英文缩写及部分概念整理(1)--博主整理_反量化 英文缩写-程序员宅基地

文章浏览阅读2.8k次。有这个想法一方面是确实很多时候会记不得一些缩写是什么意思。另外也是受 http://blog.csdn.net/lin453701006/article/details/52797415这篇博客的启发,本文主要用于自己记忆 内容主要整理自http://blog.sina.com.cn/s/blog_520811730101hmj9.html http://blog.csdn.net/feix_反量化 英文缩写

超级简单的Python爬虫入门教程(非常详细),通俗易懂,看一遍就会了_爬虫python入门-程序员宅基地

文章浏览阅读7.3k次,点赞6次,收藏36次。超级简单的Python爬虫入门教程(非常详细),通俗易懂,看一遍就会了_爬虫python入门

python怎么输出logistic回归系数_python - Logistic回归scikit学习系数与统计模型的系数 - SO中文参考 - www.soinside.com...-程序员宅基地

文章浏览阅读1.2k次。您的代码存在一些问题。首先,您在此处显示的两个模型是not等效的:尽管您将scikit-learn LogisticRegression设置为fit_intercept=True(这是默认设置),但您并没有这样做statsmodels一;来自statsmodels docs:默认情况下不包括拦截器,用户应添加。参见statsmodels.tools.add_constant。另一个问题是,尽管您处..._sm fit(method

VS2017、VS2019配置SFML_vsllfqm-程序员宅基地

文章浏览阅读518次。一、sfml官网下载32位的版本 一样的设置,64位的版本我没有成功,用不了。二、三、四以下这些内容拷贝过去:sfml-graphics-d.libsfml-window-d.libsfml-system-d.libsfml-audio-d.lib..._vsllfqm

vc——类似与beyondcompare工具的文本比较算法源代码_byoned compare 字符串比较算法-程序员宅基地

文章浏览阅读2.7k次。由于工作需要,要做一个类似bc2的文本比较工具,用红色字体标明不同的地方,研究了半天,自己写了一个简易版的。文本比较的规则是1.先比较文本的行数,2.再比较对应行的字符串的长度3.再比较每一个字符串是否相同。具体代码如下:其中m_basestr和m_mergestr里面存放是待比较的字符串int basecount=m_basestr.GetLength(); int mergec_byoned compare 字符串比较算法