首页 > 其他分享 >SftpUtil(传输工具)

SftpUtil(传输工具)

时间:2024-07-02 17:56:17浏览次数:1  
标签:String param 传输 remotePath SftpUtil new 工具 channel LOG

描述:在java项目中传输服务器数据到指定主机。

引入依赖

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

代码实现

package net.evecom.iaplatform.backup.util;

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * <B>Description: 备份工具</B>
 * </P>
 * 2024/6/25 Ryan Huang CREATE
 *
 * @author Ryan Huang
 * @version 1.0
 */
public class SftpUtil {

    private static final Logger LOG = LoggerFactory.getLogger(SftpUtil.class);

    private String username;
    private String password;
    private String host;
    private Integer port;
    private Session session;
    private ChannelSftp sftpChannel;

    public SftpUtil(String host, Integer port, String username, String password) {
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
        init();
    }

    private void init() {
        JSch jsch = new JSch();
        try {
            session = jsch.getSession(username, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            sftpChannel = (ChannelSftp) session.openChannel("sftp");
            sftpChannel.connect();
            LOG.info("SFTP连接成功");
        } catch (Exception e) {
            LOG.error("连接失败:{}", e.getMessage());
            throw new RuntimeException("无法建立SFTP连接:" + e.getMessage(), e);
        }
    }

    /**
     * 文件传输
     *
     * @param sourcePath 源目录
     * @param targetPath 目标目录
     * @param closeSource 传输完成后是否关闭资源
     */
    public void transfer(String sourcePath, String targetPath, boolean closeSource) {
        if(sourcePath == null || targetPath == null) {
            throw new IllegalArgumentException("源路径和目标路径不能为空");
        }
        try {
            uploadDirectory(sourcePath, targetPath);
            LOG.info("文件传输成功");
        } catch (Exception e) {
            LOG.error("文件传输失败:{}", e.getMessage());
            throw new RuntimeException("文件传输失败:" + e.getMessage(), e);
        } finally {
            if(closeSource) {
                // 资源泄露防护
                destroy();
            }
        }
    }

    /**
     * 保存inputStream文件到远程
     *
     * @param inputStream 流
     * @param remotePath 远程路径
     * @param remoteFileName 文件名
     * @param closeSource 是否关闭资源
     */
    public void uploadInputStreamToRemote(InputStream inputStream, String remotePath, String remoteFileName, boolean closeSource) {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()){
            byte[] buffer = new byte[1024];
            int read;
            while ((read = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, read);
            }
            byte[] fileContent = byteArrayOutputStream.toByteArray();
            String dirPath = handlePath(remotePath, "");
            sftpChannel.cd(dirPath);
            OutputStream outputStream = sftpChannel.put(remoteFileName);
            outputStream.write(fileContent);
            outputStream.flush();
            outputStream.close();

        } catch (Exception e) {
            LOG.error("文件传输失败:{}", e.getMessage());
            throw new RuntimeException("文件传输失败:" + e.getMessage(), e);
        }finally {
            if(closeSource) {
                // 资源泄露防护
                destroy();
            }
        }
    }


    /**
     * 销毁连接
     */
    public void destroy() {
        if (sftpChannel != null) {
            try {
                sftpChannel.disconnect();
            } catch (Exception e) {
                LOG.error("关闭SFTP通道失败:", e);
            }
        }
        if (session != null) {
            session.disconnect();
        }
    }


    /**
     * 上传目录
     *
     * @param localDirPath 本地目录
     * @param remoteBasePath 远程目录
     */
    private  void uploadDirectory(String localDirPath, String remoteBasePath)  {
        File localDir = new File(localDirPath);
        if (!localDir.exists() || !localDir.isDirectory()) {
            throw new IllegalArgumentException("Local path is not a valid directory.");
        }

        try {
            String remotePath = handlePath(remoteBasePath, localDir.getName());
            //目录不存在创建目录
            createRemoteDirectoriesRecursively(remotePath);

            sftpChannel.cd(remotePath);

            File[] files = localDir.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        uploadDirectory(file.getAbsolutePath(), remotePath);
                    } else {
                        String remoteFilePath = handlePath(remotePath, localDir.getName());
                        sftpChannel.put(file.getAbsolutePath(), remoteFilePath);
                    }
                }
            }
        } catch (SftpException e) {
            throw new RuntimeException("Error during SFTP operation: " + e.getMessage(), e);
        }
    }

    /**
     * 执行远程windows主机命令
     *
     * @param cmd 命令
     * @throws JSchException 异常
     * @throws IOException 异常
     */
    public int executeCmdForWindow(String cmd) throws JSchException, IOException {
        Channel channel = session.openChannel("exec");
        LOG.info("执行命令:" + cmd);
        ((ChannelExec) channel).setCommand("cmd.exe /c " + cmd);

        // 获取输出流和错误流以便读取命令执行结果
        InputStream in = channel.getInputStream();
        InputStream err = ((ChannelExec) channel).getErrStream();

        channel.connect();
        StringBuilder outputSb = new StringBuilder();
        byte[] buffer = new byte[1024];
        int status = 0;
        while (true) {
            while (in.available() > 0) {
                int i = in.read(buffer, 0, 1024);
                if (i < 0)
                    break;
                outputSb.append(new String(buffer, 0, i));
            }
            while (err.available() > 0) {
                int i = err.read(buffer, 0, 1024);
                if (i < 0)
                    break;
                outputSb.append(new String(buffer, 0, i));
            }
            if (channel.isClosed()) {
                if (in.available() > 0) continue;
                status = channel.getExitStatus();
                break;
            }
        }
        LOG.info("执行结果:" + outputSb);
        channel.disconnect();

        return status;
    }

    /**
     * 执行远程linux主机命令
     *
     * @param cmd 命令
     * @throws JSchException 异常
     * @throws IOException 异常
     */
    public int executeCmdForLinux(String cmd) throws JSchException, IOException {
        Channel channel = session.openChannel("shell");
        // 获取输入流和输出流以交互
        OutputStream input = channel.getOutputStream();
        PrintStream ps = new PrintStream(input, true);

        channel.connect();
        LOG.info("执行命令:" + cmd);
        ps.println(cmd + "; echo $?"); //添加 "; echo $?" 来获取命令的退出状态码

        BufferedReader reader = new BufferedReader(new InputStreamReader(channel.getInputStream()));
        String line;
        StringBuilder outputBuilder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            outputBuilder.append(line).append("\n");
            // 当读取到退出状态码时,跳出循环
            if (line.trim().matches("\\d+")) {
                break;
            }
        }
        String[] outArray = outputBuilder.toString().trim().split("\n");
        int exitStatus = Integer.parseInt(outArray[outArray.length - 1]);

        // 判断命令是否成功执行
        if (exitStatus == 0) {
            LOG.info("命令执行成功");
        } else {
            LOG.error("命令执行失败,退出状态码: " + outputBuilder.toString());
        }

        reader.close();
        ps.close();
        channel.disconnect();

        return exitStatus;
    }
    /**
     * 判断远程目录是否存在
     *
     * @param remotePath 远程目录
     * @return true:存在 false:不存在
     */
    private  boolean remoteDirectoryExists(String remotePath) {
        try {
            sftpChannel.stat(remotePath);
            return true;
        } catch (SftpException e) {
            if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                return false;
            } else {
                throw new RuntimeException("Error checking remote directory existence: " + e.getMessage(), e);
            }
        }
    }

    /**
     * 路径处理
     *
     * @param path 路径
     * @param fileName 文件名
     */
    public static String handlePath(String path, String fileName) {
        String str;
        str = path.replace("\\", "/");
        if (str.endsWith("/")) {
            str = str + fileName;
        } else {
            str = str + "/" + fileName;
        }

        if (path.charAt(0) != '/') {
            str = "/" + str;
        }
        return str;
    }

    /**
     * 递归创建目录
     *
     * @param remotePath 目录
     * @throws SftpException 异常
     */
    private void createRemoteDirectoriesRecursively(String remotePath) throws SftpException {
        // 分割路径以获取各级目录名
        String[] directories = remotePath.split("/");

        // 过滤掉空字符串,因为split处理绝对路径时会包含一个空元素
        List<String> validDirectories = Arrays.stream(directories)
                .filter(dir -> !dir.isEmpty())
                .collect(Collectors.toList());

        // 用于构建当前路径的StringBuilder
        StringBuilder currentPath = new StringBuilder();

        //在开头添加/代表从跟节点开始创建目录
        currentPath.append("/");
        // 遍历所有层级的目录名
        for (String dir : validDirectories) {

            // 添加目录名到当前路径,并以"/"分隔
            currentPath.append(dir).append("/");

            //:则代表磁盘路径,跳过
            if(dir.contains(":")) continue;

            // 构建完整的路径并检查是否存在
            String fullPath = currentPath.toString();
            if (!remoteDirectoryExists(fullPath)) {
                // 如果不存在,则创建该层级的目录
                sftpChannel.mkdir(fullPath);
            }
        }
    }

}

标签:String,param,传输,remotePath,SftpUtil,new,工具,channel,LOG
From: https://www.cnblogs.com/IamHzc/p/18280285

相关文章

  • 红队工具Finger 安装具体以步骤-示例centos
    1.gitclonehttps://github.com/EASY233/Finger.git如果没有yuminstallgit2.pip3install-rrequirements.txt找到finger所在的文件夹可以用find-name"Finger"进入文件中配置命令前提要安装pythonyuminstallpython-pip33.python3Finger.py-h......
  • 工具
    工具记载Zip操作importlombok.extern.slf4j.Slf4j;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.nio.file.Files;importjava.nio.file.Paths;importjava.util.zip.ZipEntry;import......
  • 统计鸟:小而美的网站流量统计工具,免费好用
    目前常见的网站流量统计平台有百度统计、GoogleAnalytics、51.LA、友盟等,但GoogleAnalytics在国内打不开、友盟已收费、百度统计限制较多、51.LA也很可能走向收费,无奈的我总算在网上搜到一款小众而好用的网站流量统计工具——统计鸟,现给大家分享下:统计鸟简介统计鸟隶属于广......
  • frp 内网穿透工具
    内网穿透FRP详细教程简介frp是一个专注于内网穿透的高性能的反向代理应用,支持TCP、UDP、HTTP、HTTPS等多种协议。可以将内网服务以安全、便捷的方式通过具有公网IP节点的中转暴露到公网。通过在具有公网IP的节点上部署frp服务端,可以轻松地将内网服务穿透到公网,同时提供......
  • C# 数据实体类生成工具 FreeSql.Generator
    安装和使用方法:传送门(大佬的学习笔记)dotnettoolinstall-gFreeSql.Generator.bat文件:__重新生成.batFreeSql.Generator-Razor"__razor.cshtml.txt"-NameOptions1,0,0,1-NameSpaceMyProject-DB"SqlServer,DataSource=192.168.1.1,1433;InitialCatalog=erp;UserID......
  • 性能测试:主流压测工具介绍
    简介性能压测工具是用于模拟大量用户访问、负载和压力条件的软件工具,以评估系统、应用程序或服务在高负载条件下的性能表现和稳定性。这些工具通常用于软件开发、测试、部署前的准备以及生产环境中的性能监测和优化。性能压测工具的主要功能包括模拟用户行为、生成大量的请求、......
  • TDengine使用taosdump工具进行数据导出导入
    数据备份(导出)可以使用命令导出sql相关文件,这些导出的相关文件可以导入时使用taosdump-o[导出文件存放路径,需要是已存在目录]-D[数据库名]导出所有数据库使用-A代替-D,后不跟数据库名,但是博主没成功,使用-D单独导出一个库是很稳定的,导出目录下包含一个sql文件和一个tdengin......
  • 自动化(爬虫)工具 DrissionPage SessionPage模式 API介绍 使用笔记(三)
    自动化(爬虫)工具DrissionPageSessionPage模式API介绍使用笔记(三)目录启动驱动启动配置常用方法(API)启动最简单的启动方式,更多启动方式见这里fromDrissionPageimportSessionPage#session_or_options:Session对象或SessionOptions对象#timeout:超时时间(秒)o......
  • 智慧旅游不再难,免费可视化工具一键搞定!
    在这个数据驱动的时代,旅游行业正以前所未有的速度转型升级,从传统的资源导向转变为精准服务与个性化体验为核心。面对海量的旅游数据,如何高效、直观地挖掘其价值,成为旅游企业提升竞争力、优化游客体验的关键。 在过去,复杂的数据分析软件和昂贵的服务费用让许多中小旅游企业望而......
  • JUC工具类: Exchanger详解
    Exchanger是用于线程协作的工具类,主要用于两个线程之间的数据交换。@立刀旁目录#带着BAT大厂的面试问题去理解Exchanger#Exchanger简介#Exchanger实现机制#Exchanger源码解析#内部类-Participant#内部类-Node#核心属性#构造函数#核心方法-exchang......