All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.extra.ssh.SshjSftp Maven / Gradle / Ivy

There is a newer version: 5.8.33
Show newest version
package cn.hutool.extra.ssh;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.AbstractFtp;
import cn.hutool.extra.ftp.FtpConfig;
import cn.hutool.extra.ftp.FtpException;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.sftp.RemoteResourceInfo;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.FileSystemFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;

/**
 * 在使用jsch 进行sftp协议下载文件时,总是中文乱码,而该框架源码又不允许设置编码。故:站在巨人的肩膀上,此类便孕育而出。
 *
 * 

* 基于sshj 框架适配。
* 参考:https://github.com/hierynomus/sshj *

* * @author youyongkun * @since 5.7.19 */ public class SshjSftp extends AbstractFtp { private SSHClient ssh; private SFTPClient sftp; private Session session; /** * 构造,使用默认端口 * * @param sshHost 主机 */ public SshjSftp(String sshHost) { this(new FtpConfig(sshHost, 22, null, null, DEFAULT_CHARSET)); } /** * 构造 * * @param sshHost 主机 * @param sshUser 用户名 * @param sshPass 密码 */ public SshjSftp(String sshHost, String sshUser, String sshPass) { this(new FtpConfig(sshHost, 22, sshUser, sshPass, CharsetUtil.CHARSET_UTF_8)); } /** * 构造 * * @param sshHost 主机 * @param sshPort 端口 * @param sshUser 用户名 * @param sshPass 密码 */ public SshjSftp(String sshHost, int sshPort, String sshUser, String sshPass) { this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, CharsetUtil.CHARSET_UTF_8)); } /** * 构造 * * @param sshHost 主机 * @param sshPort 端口 * @param sshUser 用户名 * @param sshPass 密码 * @param charset 编码 */ public SshjSftp(String sshHost, int sshPort, String sshUser, String sshPass, Charset charset) { this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, charset)); } /** * 构造 * * @param config FTP配置 * @since 5.3.3 */ protected SshjSftp(FtpConfig config) { super(config); init(); } /** * SSH 初始化并创建一个sftp客户端. * * @author youyongkun * @since 5.7.18 */ public void init() { this.ssh = new SSHClient(); ssh.addHostKeyVerifier(new PromiscuousVerifier()); try { ssh.connect(ftpConfig.getHost(), ftpConfig.getPort()); ssh.authPassword(ftpConfig.getUser(), ftpConfig.getPassword()); ssh.setRemoteCharset(ftpConfig.getCharset()); this.sftp = ssh.newSFTPClient(); } catch (IOException e) { throw new FtpException("sftp 初始化失败.", e); } } @Override public AbstractFtp reconnectIfTimeout() { if (StrUtil.isBlank(this.ftpConfig.getHost())) { throw new FtpException("Host is blank!"); } try { this.cd(StrUtil.SLASH); } catch (FtpException e) { close(); init(); } return this; } @Override public boolean cd(String directory) { String exec = String.format("cd %s", directory); command(exec); String pwd = pwd(); return pwd.equals(directory); } @Override public String pwd() { return command("pwd"); } @Override public boolean mkdir(String dir) { try { sftp.mkdir(dir); } catch (IOException e) { throw new FtpException(e); } return containsFile(dir); } @Override public List ls(String path) { List infoList; try { infoList = sftp.ls(path); } catch (IOException e) { throw new FtpException(e); } if (CollUtil.isNotEmpty(infoList)) { return CollUtil.map(infoList, RemoteResourceInfo::getName, true); } return null; } @Override public boolean delFile(String path) { try { sftp.rm(path); return !containsFile(path); } catch (IOException e) { throw new FtpException(e); } } @Override public boolean delDir(String dirPath) { try { sftp.rmdir(dirPath); return !containsFile(dirPath); } catch (IOException e) { throw new FtpException(e); } } @Override public boolean upload(String destPath, File file) { try { sftp.put(new FileSystemFile(file), destPath); return containsFile(destPath); } catch (IOException e) { throw new FtpException(e); } } @Override public void download(String path, File outFile) { try { sftp.get(path, new FileSystemFile(outFile)); } catch (IOException e) { throw new FtpException(e); } } @Override public void recursiveDownloadFolder(String sourcePath, File destDir) { List files = ls(sourcePath); if (files != null && !files.isEmpty()) { files.forEach(path -> download(sourcePath + "/" + path, destDir)); } } @Override public void close() { IoUtil.close(this.session); IoUtil.close(this.sftp); IoUtil.close(this.ssh); } /** * 是否包含该文件 * * @param fileDir 文件绝对路径 * @return true:包含 false:不包含 * @author youyongkun * @since 5.7.18 */ public boolean containsFile(String fileDir) { try { sftp.lstat(fileDir); return true; } catch (IOException e) { return false; } } /** * 执行Linux 命令 * * @param exec 命令 * @return 返回响应结果. * @author youyongkun * @since 5.7.19 */ public String command(String exec) { final Session session = this.initSession(); Session.Command command = null; try { command = session.exec(exec); InputStream inputStream = command.getInputStream(); return IoUtil.read(inputStream, this.ftpConfig.getCharset()); } catch (Exception e) { throw new FtpException(e); } finally { IoUtil.close(command); } } /** * 初始化Session并返回 * * @return session */ private Session initSession() { Session session = this.session; if (null == session || !session.isOpen()) { IoUtil.close(session); try { session = this.ssh.startSession(); } catch (final Exception e) { throw new FtpException(e); } this.session = session; } return session; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy