Java 项目如何连接并使用 SFTP 服务的示例详解

文章目录

    • 1、SFTP介绍
    • 2、pom依赖
    • 3、SFTPUtil
    • 4、测试
    • 5、测试结果

1、SFTP介绍

SFTP(Secure File Transfer Protocol)是一种安全的文件传输协议,是SSH(Secure Shell)协议的一个子协议,设计用于加密和保护文件传输的安全性。SSH本身是一种网络协议,用于在不安全的网络中提供安全的远程登录和其他安全网络服务。SFTP则在此基础上,专注于文件的安全传输。

  • 加密传输:SFTP使用加密来保护传输的数据,包括文件内容和认证信息。
  • 身份验证:SFTP使用SSH身份验证机制来验证用户身份。用户通常需要提供用户名和密码,或者使用SSH密钥对进行身份验证。
  • 文件和目录操作:SFTP支持文件和目录的上传、下载、删除、重命名和创建等操作。
  • 跨平台兼容性:SFTP是一个跨平台协议,可以在各种操作系统上使用,包括Linux、Unix、Windows等。
  • 端到端数据完整性:SFTP确保传输的文件在源和目标之间的完整性,防止数据在传输过程中被篡改或损坏。
  • 可扩展性:SFTP可以与其他协议和安全机制一起使用,以增强其功能。例如,它可以与公钥基础设施(PKI)一起使用以实现更高级的安全性。

SFTP通常用于许多场景,包括远程服务器维护、备份、文件共享和在不同计算机之间传输敏感数据。由于它提供了强大的安全性,因此特别适用于传输金融账户、公司文件和政府数据等敏感信息。

  • 端口:SFTP的默认端口与SSH相同,为22。这意味着只要sshd服务器启动了,SFTP就可使用,不需要额外安装。
  • 守护进程:SFTP本身没有单独的守护进程,它必须使用SSHD守护进程(端口号默认是22)来完成相应的连接操作。
  • 配置:SFTP的配置通常与SSH配置相关。例如,可以通过修改SSH配置文件(如sshd_config)来启用或禁用SFTP功能,以及设置相关的访问权限和安全策略。

SFTP结合了SSH的安全性和文件传输的便捷性,成为许多组织和个人在传输敏感数据时的首选协议。

2、pom依赖

SFTP需要第三方依赖进行连接。

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

3、SFTPUtil

package com.wen.util;

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;

/**
 * @author : rjw
 * @date : 2024-10-14
 */
public class SFTPUtil {
  
    private static final Logger logger = LoggerFactory.getLogger(SFTPUtil.class);

    private Session session;

    private ChannelSftp channelSftp;

	/**
	* 登录
	*/
    public boolean login(String hostname, int port, String username, String password) {
        try {
            JSch jSch = new JSch();
            // 根据用户名,IP地址获取一个session对象。
            session = jSch.getSession(username, hostname, port);
            session.setPassword(password);
            // 避免第一次连接时需要输入yes确认
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();
            logger.info("成功连接服务器");
            channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();
            logger.info("成功连接服务器");
            return true;
        } catch (JSchException e) {
            logger.error("SFTPUtil login file error:", e);
        }
        return false;
    }
	
	/**
	* 退出
	*/
    public void logout() {
        if (channelSftp != null && channelSftp.isConnected()) {
            try {
                channelSftp.disconnect();
                logger.info("成功退出 SFTP 服务器");
            } catch (Exception e) {
                logger.error("退出SFTP服务器异常: ", e);
            } finally {
                try {
                    channelSftp.disconnect(); // 关闭FTP服务器的连接
                } catch (Exception e) {
                    logger.error("关闭SFTP服务器的连接异常: ", e);
                }
            }
        }
        if (session != null && session.isConnected()) {
            try {
                session.disconnect();
                logger.info("成功退出 session 会话");
            } catch (Exception e) {
                logger.error("退出 session 会话异常: ", e);
            } finally {
                try {
                    session.disconnect(); // 关闭FTP服务器的连接
                } catch (Exception e) {
                    logger.error("关闭 session 会话的连接异常: ", e);
                }
            }
        }
    }

	/**
	* 判断是否连接
	*/
    public boolean isConnected() {
        return channelSftp != null && channelSftp.isConnected();
    }

	/**
     * 上传文件
     * 采用默认的传输模式:OVERWRITE
     *
     * @param src 输入流(文件)
     * @param dst 上传路径
     * @param fileName 上传文件名
     * @throws SftpException
     */
    public boolean upLoadFile(InputStream src, String dst, String fileName) throws SftpException {
        boolean isSuccess = false;
        try {
            if (createDir(dst)) {
                channelSftp.put(src, fileName);
                isSuccess = true;
            }
        } catch (SftpException e) {
            logger.error(fileName + "文件上传异常", e);
        }
        return isSuccess;
    }

    /**
     * 创建一个文件目录
     *
     * @param createPath 路径
     * @return
     */
    public boolean createDir(String createPath) {
        boolean isSuccess = false;
        try {
            if (isDirExist(createPath)) {
                channelSftp.cd(createPath);
                return true;
            }
            String[] pathArray = createPath.split("/");
            StringBuilder filePath = new StringBuilder("/");
            for (String path : pathArray) {
                if (path.isEmpty()) {
                    continue;
                }
                filePath.append(path).append("/");
                if (isDirExist(filePath.toString())) {
                    channelSftp.cd(filePath.toString());
                } else {
                    // 建立目录
                    channelSftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    channelSftp.cd(filePath.toString());
                }
            }
            channelSftp.cd(createPath);
            isSuccess = true;
        } catch (SftpException e) {
            logger.error("目录创建异常!", e);
        }
        return isSuccess;
    }

	/**
     * 判断目录是否存在
     *
     * @param directory 路径
     * @return
     */
    public boolean isDirExist(String directory) {
        boolean isSuccess = false;
        try {
            SftpATTRS sftpATTRS = channelSftp.lstat(directory);
            isSuccess = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
        	logger.info("SFTPUtil path has error:{}", directory);
            logger.error("SFTPUtil path has error: ", e);
            if (e.getMessage().equalsIgnoreCase("no such file")) {
                isSuccess = false;
            }
        }
        return isSuccess;
    }

    /**
     * 重命名指定文件或目录
     */
    public boolean rename(String oldPath, String newPath) {
        boolean isSuccess = false;
        try {
            channelSftp.rename(oldPath, newPath);
            isSuccess = true;
        } catch (SftpException e) {
            logger.error("重命名指定文件或目录异常", e);
        }
        return isSuccess;
    }
    
    /**
     * 列出指定目录下的所有文件和子目录。
     */
    public Vector ls(String path) {
        try {
            Vector vector = channelSftp.ls(path);
            return vector;
        } catch (SftpException e) {
            logger.error("列出指定目录下的所有文件和子目录。", e);
        }
        return null;
    }

	/**
     * 删除文件
     */
	public boolean deleteFile(String directory, String deleteFile) {
        boolean isSuccess = false;
        try {
            channelSftp.cd(directory);
            channelSftp.rm(deleteFile);
            isSuccess = true;
        } catch (SftpException e) {
            logger.error("删除文件失败", e);
        }
        return isSuccess;
    }

    /**
     * 下载文件
     *
     * @param directory 下载目录
     * @param downloadFile 下载的文件
     * @param saveFile 下载到本地路径
     */
    public boolean download(String directory, String downloadFile, String saveFile) {
        boolean isSuccess = false;
        try {
            channelSftp.cd(directory);
            File file = new File(saveFile);
            channelSftp.get(downloadFile, new FileOutputStream(file));
            isSuccess = true;
        } catch (SftpException e) {
            logger.error("下载文件失败", e);
        } catch (FileNotFoundException e) {
            logger.error("下载文件失败", e);
        }
        return isSuccess;
    }

	/**
     * 输出指定文件流
     */
	public InputStream getFile(String path) {
		try {
			InputStream inputStream = channelSftp.get(path);
			return inputStream;
		} catch (SftpException e) {
            throw new RuntimeException(e);
        }
	}

    /**
     * 下载文件,新
     */
    public InputStream downloadFile(String remoteFileName, String remoteFilePath) {
        InputStream input = null;
        try {
            if (!isDirExist(remoteFilePath)) {
                logger.info("SFTPUtil not changeWorkingDirectory.filename:{},Path:{}", remoteFileName, remoteFilePath);
                logout();
                return input;
            }
            logger.info("SFTPUtil Info filename:{},Path:{}", remoteFileName, remoteFilePath);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            input = new ByteArrayInputStream(outputStream.toByteArray());
            outputStream.close();
            logger.info("file download. filename:{},Path:{}", remoteFileName, remoteFilePath);
        } catch (Exception e) {
            logger.error("SFTPUtil download file error:", e);
            logout();
        }
        return input;
    }

	/**
     * 验证sftp文件是否有效(判断文件属性的日期)
     */
    public String validateSourceData(String fileName, String remoteFilePath, Date nowTime) throws IOException, SftpException {
        Date temp = null;
        if (!isDirExist(remoteFilePath)) {
            logout();
            return "尝试切换SFTP路径失败, 文件路径: " + remoteFilePath + fileName;
        }
        Vector vector = channelSftp.ls(remoteFilePath);
        for (int i = 0; i < vector.capacity(); i++) {
            ChannelSftp.LsEntry data = (ChannelSftp.LsEntry) vector.get(i);
            if (data.getFilename().equalsIgnoreCase(fileName)) {
                temp = new Date(data.getAttrs().getMTime() * 1000L);
                //logger.info("时间: timeStamp:{},nowTime:{}",temp,nowTime);
                if (temp.getTime() == nowTime.getTime()) {
                    return "SFTP文件没有更新";
                }
                nowTime.setTime(temp.getTime());
                break;
            }
        }
        //logout();
        return null;
    }


	/**
     * IP
     */
    public String getSFTPHost() {
        return session.getHost();
    }

	/**
     * 端口
     */
    public int getSFTPPort() {
        return session.getPort();
    }
}

4、测试

public class Test {

	private static SFTPUtil sftpUtil = new SFTPUtil();

	public static String convertInputStreamToString(InputStream inputStream) throws IOException{
        StringBuilder stringBuilder = new StringBuilder();
        try{
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            String line;
            while ((line = bufferedReader.readLine()) != null){
                System.out.println(line);
                stringBuilder.append(line).append("\n");
            }
        }catch (Exception e){
            System.out.println(e);
        }
        if(stringBuilder.length() > 0 && stringBuilder.charAt(stringBuilder.length() - 1) == '\n'){
            stringBuilder.setLength(stringBuilder.length() - 1);
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        boolean connected = sftpUtil.isConnected();
        if (!connected) {
            System.out.println("连接SFTP");
            // 折里可以采用配置文件 @Value 注解
            connected = sftpUtil.login("10.26.73.163", 2222, "username", "password");
        }
        if (connected) {
            System.out.println("连接成功");
            System.out.println(sftpUtil.getSFTPHost() + " : " + sftpUtil.getSFTPPort());
            InputStream inputStream = sftpUtil.getFile("/rjw/wind.txt");
            String s = convertInputStreamToString(inputStream);
            System.out.println(s);
            File file = new File("C:\\Users\\wen\\Desktop\\sun.txt");
            InputStream inputStream1 = Files.newInputStream(file.toPath());
            boolean dir = sftpUtil.upLoadFile(inputStream1, "/rjw", "big.txt");
            System.out.println("添加文件成功: " + dir);
            sftpUtil.logout();
        }
    }
}

5、测试结果

SFTP测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/894442.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

测试代理IP的有效性和可用性:全面方法与技巧

使用代理IP的有效性和可用性直接关系到用户的工作效率&#xff0c;尤其是在进行数据抓取、网络爬虫和保护个人隐私等场景中。然而&#xff0c;如果代理IP的质量不佳&#xff0c;或者无法正常工作&#xff0c;就可能导致操作中断、数据丢失&#xff0c;甚至影响整个项目的进度。…

《OpenCV计算机视觉》——人脸检测__Haar特征、级联分类器

文章目录 Haar特征一、定义与原理二、分类三、计算方法四、应用五、优缺点 级联分类器一、定义与原理二、结构与组成三、举例说明 Haar特征 Haar特征是一种在计算机视觉和图像处理中常用的特征描述方法&#xff0c;特别适用于物体识别&#xff0c;尤其是人脸检测。以下是对Haa…

一次性入门三款分布式定时任务调度框架:Quartz、ElasticJob3.0、xxl-job

分布式定时任务调度框架&#xff08;文末有源码&#xff09; 前言1、Quartz1.1 数据库1.2 maven依赖1.3 代码实现1.3.1 创建一个job1.3.1 为job设置trigger 1.4 配置文件1.5 启动、测试1.1 单机1.2 集群 2、ElasticJob2.1 下载zk2.2 新建三个类型的作业2.3 配置文件2.4 启动项目…

基于Java微信小程序的水果销售系统详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

创客项目秀 | 基于使用 XIAO BLE Sense 和 Edge Impulse 的宠物活动跟踪器

今天为大家带来的是来自美国的创作者米顿-达斯的作品:宠物活动跟踪器.这个装置主要是为宠物主人提供关于宠物日常活动量的详尽数据&#xff0c;还能够根据宠物的独特需求&#xff0c;提供个性化的健康建议和活动指导。 项目背景 为了全面促进宠物的健康与活力&#xff0c;采用…

Python 数值计算与数值分析基础

Python 数值计算与数值分析基础 示例演示 当涉及到Python数值计算和数值分析时&#xff0c;下面是20个示例&#xff0c;涵盖了一些常见的用法&#xff1a; 1.数值积分&#xff1a; 在 Python 中&#xff0c;你可以使用 scipy.integrate 模块中的 quad 函数来进行数值积分 …

【Linux驱动开发】通过ioremap虚拟内存映射的寄存器操作驱动、C应用函数库开发 devmem命令测试(正点原子STM32MP135文档BUG)

【Linux驱动开发】通过ioremap虚拟内存映射的寄存器操作驱动、C应用函数库开发 devmem命令测试&#xff08;正点原子STM32MP135文档BUG&#xff09; 【Linux驱动开发】通过ioremap虚拟内存映射的寄存器操作驱动 devmem命令测试 gitee库&#xff1a; https://gitee.com/Mike_Zho…

记一次Netty模拟压测应用开发

背景 最近需要开发一个上游端模拟数据推送&#xff0c;测试高流量下下游的业务功能处理速度&#xff0c;大致架构如下 准备工作 构造消息体&#xff0c;由于是模拟大量数据推送并没有业务逻辑&#xff0c;所以我们使用池化的directBuffer增加推送消息以及减少创建和消费buf…

13.1 Linux_网络编程_TCP/UDP

字节序 1、概述 什么是字节序&#xff1a; 字节序就是字节的存储顺序&#xff0c;分为大端字节序和小端字节序。 大端字节序&#xff1a;低地址存高位&#xff08;网络&#xff09;小端字节序&#xff1a;低地址存低位&#xff08;主机&#xff09; 检验主机字节序模式&…

Java @RequestPart注解:同时实现文件上传与JSON对象传参

RequestPart注解&#xff1a;用于处理multipart/form-data请求的一部分&#xff0c;通常用于文件上传或者处理表单中的字段。 java后端举例&#xff1a; PostMapping("/fileTest")public AjaxResult fileTest(RequestPart("file") MultipartFile file,Req…

【时间之外】IT人求职和创业应知【10】

认知决定你的赚钱能力。以下是今天可能影响你求职和创业的热点新闻: 今日关键字:SFISF【互换便利】 1. 央行推出股票回购增持再贷款,科技股全线爆发 新闻概要: 2024年10月18日,央行等三部门联合发布《关于设立股票回购增持再贷款有关事宜的通知》,同时表示年底有进一步…

基于GeoScene Pro的开源数据治理与二维制图规范化处理智能工具箱

内容导读 本文描述的是一个基于GeoScene Pro4.0/ArcGIS3.1 Pro平台的开源数据治理与二维制图规范化处理智能工具箱(免费试用&#xff0c;文末有获取方式)&#xff0c;旨在解决GIS应用中数据转换、检查、治理和制图数据规范化处理方面的问题。 工具箱结合了Geoscene/ArcGIS Pr…

Asp.net Core SignalR 跨域设置(Furion)

前端VUE2.0/3.0 后端NET8.0/NET6.0 框架Furion 前端安装SignalR通信库&#xff0c;下面任意一条安装指令都可以&#xff0c;根据项目自行选择 npm install microsoft/signalr yarn add microsoft/signalr前端使用 <script> import { HubConnectionBuilder } from micr…

[Halcon矩阵] 通过手眼标定矩阵计算相机旋转角度

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…

SpringBoot教程(三十二) | SpringBoot集成Skywalking链路跟踪

SpringBoot教程&#xff08;三十二&#xff09; | SpringBoot集成Skywalking链路跟踪 一、Skywalking是什么&#xff1f;二、Skywalking与JDK版本的对应关系三、Skywalking下载四、Skywalking 数据存储五、Skywalking 的启动六、部署探针前提&#xff1a; Agents 8.9.0 放入 项…

C#从零开始学习(用unity探索C#)(unity Lab1)

初次使用Unity 本章所有的代码都放在 https://github.com/hikinazimi/head-first-Csharp Unity的下载与安装 从 unity官网下载Unity Hub Unity的使用 安装后,注册账号,下载unity版本,然后创建3d项目 设置窗口界面布局 3D对象的创建 点击对象,然后点击Move Guzmo,就可以拖动…

云服务解决方案,针对小程序、网页、HTML5等轻量化视频解决方案

无论是社交媒体上的短视频分享&#xff0c;还是企业官网中的产品展示&#xff0c;亦或是教育平台上的互动课程&#xff0c;高质量、易制作的视频内容正以前所未有的速度改变着我们的生活方式和工作模式。然而&#xff0c;面对多样化的发布平台和日益增长的个性化需求&#xff0…

Python从0到100(六十五):Python OpenCV-图像运颜色转换及几何变换

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

.net 根据html的input type=“week“控件的值获取星期一和星期日的日期

初始化 "week" 控件值&#xff1a; //MVC部分 public ActionResult WeeklyList() {int weekNo new GregorianCalendar().GetWeekOfYear(System.DateTime.Now, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday);string DefaultWeek DateTime.No…

ssm医院交互系统+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 摘要 I Abstract II 1绪论 1 1.1研究背景与意义 1 1.1.1研究背景 1 1.1.2研究意义 1 1.2国内外研究…