目录
- 1. JSCH简介
- 2. JSCH依赖
- 3. 使用方法
- 3.1 连接远程主机
- 3.2 ChannelExec使用说明
- 3.3 ChannelSftp使用说明
- 3.4 ChannelShell使用说明
- 3.5 完整工具类代码
- 4. 使用连接池
1. JSCH简介
JSch 是SSH2的一个纯Java实现。它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文件传输等等。
你可以将它的功能集成到你自己的 程序中。同时该项目也提供一个J2ME版本用来在手机上直连SSHD服务器。
2. JSCH依赖
<dependency> | |
<groupId>com.jcraft</groupId> | |
<artifactId>jsch</artifactId> | |
<version>0.1.55</version> | |
</dependency> |
3. 使用方法
3.1 连接远程主机
/** | |
* 初始化 | |
* | |
* @param ip 远程主机IP地址 | |
* @param port 远程主机端口 | |
* @param username 远程主机登陆用户名 | |
* @param password 远程主机登陆密码 | |
* @throws JSchException JSch异常 | |
*/ | |
public void init(String ip, Integer port, String username, String password) throws JSchException { | |
JSch jsch = new JSch(); | |
session = jsch.getSession(username, ip, port); | |
session.setPassword(password); | |
Properties sshConfig = new Properties(); | |
sshConfig.put("StrictHostKeyChecking", strictHostKeyChecking); | |
session.setConfig(sshConfig); | |
session.connect(timeout); | |
log.info("Session connected!"); | |
} | |
public void init(String ip, String username, String password) throws JSchException { | |
init(ip,22,username,password); | |
} |
3.2 ChannelExec使用说明
/** | |
* 连接多次执行命令,执行命令完毕后需要执行close()方法 | |
* | |
* @param command 需要执行的指令 | |
* @return 执行结果 | |
* @throws Exception 没有执行初始化 | |
*/ | |
public String execCmd(String command) throws Exception { | |
// 打开执行shell指令的通道 | |
channel = session.openChannel("exec"); | |
channelExec = (ChannelExec) channel; | |
if (session == null || channel == null || channelExec == null) { | |
log.error("请先执行init()"); | |
throw new Exception("请先执行init()"); | |
} | |
log.info("execCmd command - > {}", command); | |
channelExec.setCommand(command); | |
channel.setInputStream(null); | |
channelExec.setErrStream(System.err); | |
channel.connect(); | |
StringBuilder sb = new StringBuilder(16); | |
try (InputStream in = channelExec.getInputStream(); | |
InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8); | |
BufferedReader reader = new BufferedReader(isr)) { | |
String buffer; | |
while ((buffer = reader.readLine()) != null) { | |
sb.append("\n").append(buffer); | |
} | |
log.info("execCmd result - > {}", sb); | |
return sb.toString(); | |
} | |
} | |
/** | |
* 执行命令关闭连接 | |
* @param command 需要执行的指令 | |
* @return 执行结果 | |
* @throws Exception 没有执行初始化 | |
*/ | |
public String execCmdAndClose(String command) throws Exception { | |
String result = execCmd(command); | |
close(); | |
return result; | |
} | |
/** | |
* 释放资源 | |
*/ | |
public void close() { | |
if (channelExec != null && channelExec.isConnected()) { | |
channelExec.disconnect(); | |
} | |
if (channel != null && channel.isConnected()) { | |
channel.disconnect(); | |
} | |
if (session != null && session.isConnected()) { | |
session.disconnect(); | |
} | |
} |
3.3 ChannelSftp使用说明
3.3.1 ChannelSftp简介
ChannelSftp类是JSch实现SFTP核心类,它包含了所有SFTP的方法,如:
put()
: 文件上传get()
: 文件下载cd()
: 进入指定目录ls()
: 得到指定目录下的文件列表rename()
: 重命名指定文件或目录rm()
: 删除指定文件mkdir()
: 创建目录rmdir()
: 删除目录
3.3.2 JSch支持三种文件传输模式:
模式 | 描述 |
OVERWRITE | 完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。 |
RESUME | 恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,则会从上一次中断的地方续传。 |
APPEND | 追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。 |
3.3.3 文件上传
实现文件上传可以调用ChannelSftp对象的put方法。ChannelSftp中有12个put方法的重载方法:
方法 | 描述 |
public void put(String src, String dst) | 将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。采用默认的传输模式:OVERWRITE |
public void put(String src, String dst, int mode) | 将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。指定文件传输模式为mode(mode可选值为:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,ChannelSftp.APPEND) |
public void put(String src, String dst, SftpProgressMonitor monitor) | 将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。采用默认的传输模式:OVERWRITE,并使用实现了SftpProgressMonitor接口的monitor对象来监控文件传输的进度。 |
public void put(String src, String dst,SftpProgressMonitor monitor, int mode) | 将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。指定传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控文件传输的进度。 |
public void put(InputStream src, String dst) | 将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。采用默认的传输模式:OVERWRITE |
public void put(InputStream src, String dst, int mode) | 将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode |
public void put(InputStream src, String dst, SftpProgressMonitor monitor) | 将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。采用默认的传输模式:OVERWRITE,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。 |
public void put(InputStream src, String dst,SftpProgressMonitor monitor, int mode) | 将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。 |
public OutputStream put(String dst) | 该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。采用默认的传输模式:OVERWRITE |
public OutputStream put(String dst, final int mode) | 该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode |
public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) | 该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。 |
public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) | 该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。offset指定了一个偏移量,从输出流偏移offset开始写入数据。 |
/** | |
* SFTP文件上传 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putAndClose(String src, String dst) throws Exception { | |
putAndClose(src, dst, ChannelSftp.OVERWRITE); | |
} | |
/** | |
* SFTP文件上传 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @param mode 上传模式 默认为ChannelSftp.OVERWRITE | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putAndClose(String src, String dst, int mode) throws Exception { | |
initChannelSftp(); | |
log.info("Upload File {} -> {}", src, dst); | |
channelSftp.put(src, dst, mode); | |
log.info("Upload File Success!"); | |
close(); | |
} | |
/** | |
* SFTP文件上传并监控上传进度 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putMonitorAndClose(String src, String dst) throws Exception { | |
putMonitorAndClose(src, dst, ChannelSftp.OVERWRITE); | |
} | |
/** | |
* SFTP文件上传并监控上传进度 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @param mode 上传模式 默认为ChannelSftp.OVERWRITE | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putMonitorAndClose(String src, String dst, int mode) throws Exception { | |
initChannelSftp(); | |
UploadMonitor monitor = new UploadMonitor(new File(src).length()); | |
log.info("Upload File {} -> {}", src, dst); | |
channelSftp.put(src, dst, monitor, mode); | |
log.info("Upload File Success!"); | |
close(); | |
} | |
/** | |
* 释放资源 | |
*/ | |
public void close() { | |
if (channelSftp != null && channelSftp.isConnected()) { | |
channelSftp.disconnect(); | |
} | |
if (channel != null && channel.isConnected()) { | |
channel.disconnect(); | |
} | |
if (session != null && session.isConnected()) { | |
session.disconnect(); | |
} | |
} | |
private void initChannelSftp() throws Exception { | |
channel = session.openChannel("sftp"); | |
channel.connect(); // 建立SFTP通道的连接 | |
channelSftp = (ChannelSftp) channel; | |
if (session == null || channel == null || channelSftp == null) { | |
log.error("请先执行init()"); | |
throw new Exception("请先执行init()"); | |
} | |
} | |
} |
3.3.4 文件下载
JSch文件下载是通过调用ChannelSftp对象的get方法来实现的。ChannelSftp中有9个get方法的重载方法:
方法 | 描述 |
publicvoid get(String src, String dst) | 将目标服务器上文件名为src的文件下载到本地,本地文件名为dst。若dst为目录,则下载到本地的文件名将与src文件名相同。(注:src必须是文件,不能为目录),采用默认的传输模式:OVERWRITE |
publicvoid get(String src, String dst, SftpProgressMonitor monitor) | 将目标服务器上文件名为src的文件下载到本地,本地文件名为dst。若dst为目录,则下载到本地的文件名将与src文件名相同。(注:src必须是文件,不能为目录),采用默认的传输模式:OVERWRITE |
publicvoid get(String src, String dst,SftpProgressMonitor monitor, int mode) | 将目标服务器上文件名为src的文件下载到本地,本地文件名为dst。若dst为目录,则下载到本地的文件名将与src文件名相同。(注:src必须是文件,不能为目录)指定文件传输模式为mode(mode可选值为:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,ChannelSftp.APPEND),并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。 |
publicvoid get(String src, OutputStream dst) | 将目标服务器上文件名为src的文件下载到本地,下载的数据写入到输出流对象dst(如:文件输出流)。采用默认的传输模式:OVERWRITE |
publicvoid get(String src, OutputStream dst, SftpProgressMonitor monitor) | 将目标服务器上文件名为src的文件下载到本地,下载的数据写入到输出流对象dst(如:文件输出流)。采用默认的传输模式:OVERWRITE,并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。 |
publicvoid get(String src, OutputStream dst, SftpProgressMonitor monitor, int mode, long skip) | 将目标服务器上文件名为src的文件下载到本地,下载的数据写入到输出流对象dst(如:文件输出流)。指定文件传输模式为mode并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。skip指定了一个跳读量,即下载时从src文件跳过skip字节的数据。(一般不推荐使用该参数,默认设为0) |
public InputStream get(String src) | 该方法返回一个输入流,该输入流含有目标服务器上文件名为src的文件数据。可以从该输入流中读取数据,最终将数据传输到本地(如:读取数据后将数据写入到本地的文件中)(注:该方法不支持多种文件传输模式,如何读取与保存数据由应用程序自己确定) |
public InputStream get(String src, SftpProgressMonitor monitor) | 该方法返回一个输入流,该输入流含有目标服务器上文件名为src的文件数据。可以从该输入流中读取数据,最终将数据传输到本地(如:读取数据后将数据写入到本地的文件中)并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。(注:该方法不支持多种文件传输模式,如何读取与保存数据由应用程序自己确定) |
public InputStream get(String src, final SftpProgressMonitor monitor, finallong skip) | 该方法返回一个输入流,该输入流含有目标服务器上文件名为src的文件数据。可以从该输入流中读取数据,最终将数据传输到本地(如:读取数据后将数据写入到本地的文件中)并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。(注:该方法不支持多种文件传输模式,如何读取与保存数据由应用程序自己确定)skip指定了一个跳读量,即下载时从src文件跳过skip字节的数据。(一般不推荐使用该参数,默认设为0) |
/** | |
* SFTP文件下载 | |
* | |
* @param src 源文件地址 | |
* @param dst 目的地址 | |
* @throws Exception 下载文件失败 | |
*/ | |
public void getAndClose(String src, String dst) throws Exception { | |
initChannelSftp(); | |
log.info("Download File {} -> {}", src, dst); | |
channelSftp.get(src, dst); | |
log.info("Download File Success!"); | |
close(); | |
} | |
public void getMonitorAndClose(String src, String dst) throws Exception { | |
initChannelSftp(); | |
FileProgressMonitor monitor = new FileProgressMonitor(new File(src).length()); | |
log.info("Download File {} -> {}", src, dst); | |
channelSftp.get(src, dst, monitor); | |
log.info("Download File Success!"); | |
close(); | |
} |
3.4 ChannelShell使用说明
3.4.1 shell代码
/** | |
* 执行复杂shell命令 | |
* @param cmds 多条命令 | |
* @return 执行结果 | |
* @throws Exception 连接异常 | |
*/ | |
public String execCmdByShell(String... cmds)throws Exception{ | |
return execCmdByShell(Arrays.asList(cmds)); | |
} | |
/** | |
* 执行复杂shell命令 | |
* @param cmds 多条命令 | |
* @return 执行结果 | |
* @throws Exception 连接异常 | |
*/ | |
public String execCmdByShell(List<String> cmds) throws Exception { | |
String result = ""; | |
initChannelShell(); | |
InputStream inputStream = channelShell.getInputStream(); | |
channelShell.setPty(true); | |
channelShell.connect(); | |
OutputStream outputStream = channelShell.getOutputStream(); | |
PrintWriter printWriter = new PrintWriter(outputStream); | |
for (String cmd : cmds) { | |
printWriter.println(cmd); | |
} | |
printWriter.flush(); | |
byte[] tmp = new byte[1024]; | |
while (true) { | |
while (inputStream.available() > 0) { | |
int i = inputStream.read(tmp, 0, 1024); | |
if (i < 0) { | |
break; | |
} | |
String s = new String(tmp, 0, i); | |
if (s.contains("--More--")) { | |
outputStream.write((" ").getBytes()); | |
outputStream.flush(); | |
} | |
System.out.println(s); | |
} | |
if (channelShell.isClosed()) { | |
System.out.println("exit-status:" + channelShell.getExitStatus()); | |
break; | |
} | |
try { | |
Thread.sleep(1000); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
outputStream.close(); | |
inputStream.close(); | |
return result; | |
} | |
private void initChannelShell() throws Exception { | |
// 打开执行shell指令的通道 | |
channel = session.openChannel("shell"); | |
channelShell = (ChannelShell) channel; | |
if (session == null || channel == null || channelShell == null) { | |
log.error("请先执行init()"); | |
throw new Exception("请先执行init()"); | |
} | |
} |
3.5 完整工具类代码
ShellUtil.java
public class ShellUtil { | |
private String strictHostKeyChecking; | |
private Integer timeout; | |
private Session session; | |
private Channel channel; | |
private ChannelExec channelExec; | |
private ChannelSftp channelSftp; | |
private ChannelShell channelShell; | |
/** | |
* 初始化 | |
* | |
* @param ip 远程主机IP地址 | |
* @param port 远程主机端口 | |
* @param username 远程主机登陆用户名 | |
* @param password 远程主机登陆密码 | |
* @throws JSchException JSch异常 | |
*/ | |
public void init(String ip, Integer port, String username, String password) throws JSchException { | |
JSch jsch = new JSch(); | |
session = jsch.getSession(username, ip, port); | |
session.setPassword(password); | |
Properties sshConfig = new Properties(); | |
sshConfig.put("StrictHostKeyChecking", strictHostKeyChecking); | |
session.setConfig(sshConfig); | |
session.connect(timeout); | |
log.info("Session connected!"); | |
} | |
public void init(String ip, String username, String password) throws JSchException { | |
init(ip, 22, username, password); | |
} | |
/** | |
* 连接多次执行命令,执行命令完毕后需要执行close()方法 | |
* | |
* @param command 需要执行的指令 | |
* @return 执行结果 | |
* @throws Exception 没有执行初始化 | |
*/ | |
public String execCmd(String command) throws Exception { | |
initChannelExec(); | |
log.info("execCmd command - > {}", command); | |
channelExec.setCommand(command); | |
channel.setInputStream(null); | |
channelExec.setErrStream(System.err); | |
channel.connect(); | |
StringBuilder sb = new StringBuilder(16); | |
try (InputStream in = channelExec.getInputStream(); | |
InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8); | |
BufferedReader reader = new BufferedReader(isr)) { | |
String buffer; | |
while ((buffer = reader.readLine()) != null) { | |
sb.append("\n").append(buffer); | |
} | |
log.info("execCmd result - > {}", sb); | |
return sb.toString(); | |
} | |
} | |
/** | |
* 执行命令关闭连接 | |
* | |
* @param command 需要执行的指令 | |
* @return 执行结果 | |
* @throws Exception 没有执行初始化 | |
*/ | |
public String execCmdAndClose(String command) throws Exception { | |
String result = execCmd(command); | |
close(); | |
return result; | |
} | |
/** | |
* 执行复杂shell命令 | |
* | |
* @param cmds 多条命令 | |
* @return 执行结果 | |
* @throws Exception 连接异常 | |
*/ | |
public String execCmdByShell(String... cmds) throws Exception { | |
return execCmdByShell(Arrays.asList(cmds)); | |
} | |
/** | |
* 执行复杂shell命令 | |
* | |
* @param cmds 多条命令 | |
* @return 执行结果 | |
* @throws Exception 连接异常 | |
*/ | |
public String execCmdByShell(List<String> cmds) throws Exception { | |
String result = ""; | |
initChannelShell(); | |
InputStream inputStream = channelShell.getInputStream(); | |
channelShell.setPty(true); | |
channelShell.connect(); | |
OutputStream outputStream = channelShell.getOutputStream(); | |
PrintWriter printWriter = new PrintWriter(outputStream); | |
for (String cmd : cmds) { | |
printWriter.println(cmd); | |
} | |
printWriter.flush(); | |
byte[] tmp = new byte[1024]; | |
while (true) { | |
while (inputStream.available() > 0) { | |
int i = inputStream.read(tmp, 0, 1024); | |
if (i < 0) { | |
break; | |
} | |
String s = new String(tmp, 0, i); | |
if (s.contains("--More--")) { | |
outputStream.write((" ").getBytes()); | |
outputStream.flush(); | |
} | |
System.out.println(s); | |
} | |
if (channelShell.isClosed()) { | |
System.out.println("exit-status:" + channelShell.getExitStatus()); | |
break; | |
} | |
try { | |
Thread.sleep(1000); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
outputStream.close(); | |
inputStream.close(); | |
return result; | |
} | |
/** | |
* SFTP文件上传 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putAndClose(String src, String dst) throws Exception { | |
putAndClose(src, dst, ChannelSftp.OVERWRITE); | |
} | |
/** | |
* SFTP文件上传 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @param mode 上传模式 默认为ChannelSftp.OVERWRITE | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putAndClose(String src, String dst, int mode) throws Exception { | |
put(src, dst, mode); | |
close(); | |
} | |
public void put(String src, String dst) throws Exception { | |
put(src, dst, ChannelSftp.OVERWRITE); | |
} | |
public void put(String src, String dst, int mode) throws Exception { | |
initChannelSftp(); | |
log.info("Upload File {} -> {}", src, dst); | |
channelSftp.put(src, dst, mode); | |
log.info("Upload File Success!"); | |
} | |
/** | |
* SFTP文件上传并监控上传进度 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putMonitorAndClose(String src, String dst) throws Exception { | |
putMonitorAndClose(src, dst, ChannelSftp.OVERWRITE); | |
} | |
/** | |
* SFTP文件上传并监控上传进度 | |
* | |
* @param src 源地址 | |
* @param dst 目的地址 | |
* @param mode 上传模式 默认为ChannelSftp.OVERWRITE | |
* @throws Exception 上传文件失败 | |
*/ | |
public void putMonitorAndClose(String src, String dst, int mode) throws Exception { | |
initChannelSftp(); | |
FileProgressMonitor monitor = new FileProgressMonitor(new File(src).length()); | |
log.info("Upload File {} -> {}", src, dst); | |
channelSftp.put(src, dst, monitor, mode); | |
log.info("Upload File Success!"); | |
close(); | |
} | |
/** | |
* SFTP文件下载 | |
* | |
* @param src 源文件地址 | |
* @param dst 目的地址 | |
* @throws Exception 下载文件失败 | |
*/ | |
public void getAndClose(String src, String dst) throws Exception { | |
get(src,dst); | |
close(); | |
} | |
public void get(String src, String dst) throws Exception { | |
initChannelSftp(); | |
log.info("Download File {} -> {}", src, dst); | |
channelSftp.get(src, dst); | |
log.info("Download File Success!"); | |
} | |
/** | |
* SFTP文件下载并监控下载进度 | |
* | |
* @param src 源文件地址 | |
* @param dst 目的地址 | |
* @throws Exception 下载文件失败 | |
*/ | |
public void getMonitorAndClose(String src, String dst) throws Exception { | |
initChannelSftp(); | |
FileProgressMonitor monitor = new FileProgressMonitor(new File(src).length()); | |
log.info("Download File {} -> {}", src, dst); | |
channelSftp.get(src, dst, monitor); | |
log.info("Download File Success!"); | |
close(); | |
} | |
/** | |
* 删除指定目录文件 | |
* | |
* @param path 删除路径 | |
* @throws Exception 远程主机连接异常 | |
*/ | |
public void deleteFile(String path) throws Exception { | |
initChannelSftp(); | |
channelSftp.rm(path); | |
log.info("Delete File {}", path); | |
} | |
/** | |
* 删除指定目录 | |
* | |
* @param path 删除路径 | |
* @throws Exception 远程主机连接异常 | |
*/ | |
public void deleteDir(String path) throws Exception { | |
initChannelSftp(); | |
channelSftp.rmdir(path); | |
log.info("Delete Dir {} ", path); | |
} | |
/** | |
* 释放资源 | |
*/ | |
public void close() { | |
if (channelSftp != null && channelSftp.isConnected()) { | |
channelSftp.disconnect(); | |
} | |
if (channelExec != null && channelExec.isConnected()) { | |
channelExec.disconnect(); | |
} | |
if (channel != null && channel.isConnected()) { | |
channel.disconnect(); | |
} | |
if (session != null && session.isConnected()) { | |
session.disconnect(); | |
} | |
} | |
private void initChannelSftp() throws Exception { | |
channel = session.openChannel("sftp"); | |
channel.connect(); // 建立SFTP通道的连接 | |
channelSftp = (ChannelSftp) channel; | |
if (session == null || channel == null || channelSftp == null) { | |
log.error("请先执行init()"); | |
throw new Exception("请先执行init()"); | |
} | |
} | |
private void initChannelExec() throws Exception { | |
// 打开执行shell指令的通道 | |
channel = session.openChannel("exec"); | |
channelExec = (ChannelExec) channel; | |
if (session == null || channel == null || channelExec == null) { | |
log.error("请先执行init()"); | |
throw new Exception("请先执行init()"); | |
} | |
} | |
private void initChannelShell() throws Exception { | |
// 打开执行shell指令的通道 | |
channel = session.openChannel("shell"); | |
channelShell = (ChannelShell) channel; | |
if (session == null || channel == null || channelShell == null) { | |
log.error("请先执行init()"); | |
throw new Exception("请先执行init()"); | |
} | |
} | |
} |
FileProgressMonitor.java
public class FileProgressMonitor extends TimerTask implements SftpProgressMonitor { | |
private boolean isEnd = false; | |
private long transfered; | |
private long fileSize; | |
private ScheduledExecutorService executorService; | |
private boolean isScheduled = false; | |
long startTime = 0L; | |
public FileProgressMonitor(long fileSize) { | |
this.fileSize = fileSize; | |
} | |
public void run() { | |
if (!isEnd()) { | |
log.info("Transfering is in progress."); | |
long transfered = getTransfered(); | |
// 判断当前已传输数据大小是否等于文件总大小 | |
if (transfered != fileSize) { | |
log.info("Current transfered: {} bytes", transfered); | |
sendProgressMessage(transfered); | |
} else { | |
// 如果当前已传输数据大小等于文件总大小,说明已完成,设置end | |
log.info("File transfering is done."); | |
setEnd(true); | |
} | |
} else { | |
log.info("Transfering done. Cancel timer."); | |
// 如果传输结束,停止timer记时器 | |
stop(); | |
return; | |
} | |
} | |
/** | |
* 实现了SftpProgressMonitor接口的count方法 | |
*/ | |
public boolean count(long count) { | |
if (isEnd()) { | |
return false; | |
} | |
if (!isScheduled) { | |
start(); | |
} | |
add(count); | |
return true; | |
} | |
/** | |
* 实现了SftpProgressMonitor接口的end方法 | |
*/ | |
public void end() { | |
setEnd(true); | |
log.info("transfering end. time ->{} s", (System.currentTimeMillis() - startTime) / 1000); | |
} | |
public void init(int op, String src, String dest, long max) { | |
startTime = System.currentTimeMillis(); | |
} | |
public void stop() { | |
log.info("Try to stop progress monitor."); | |
boolean isShutdown = executorService.isShutdown(); | |
if (!isShutdown) { | |
executorService.shutdown(); | |
} | |
log.info("Progress monitor stoped."); | |
} | |
public void start() { | |
log.info("Try to start progress monitor."); | |
executorService = new ScheduledThreadPoolExecutor(1); | |
//1秒钟后开始执行,每2杪钟执行一次 | |
executorService.scheduleWithFixedDelay(this, 1, 1, TimeUnit.SECONDS); | |
isScheduled = true; | |
log.info("Progress monitor started."); | |
} | |
/** | |
* 打印progress信息 | |
* | |
* @param transfered | |
*/ | |
private void sendProgressMessage(long transfered) { | |
if (fileSize != 0) { | |
double d = ((double) transfered * 100) / (double) fileSize; | |
DecimalFormat df = new DecimalFormat("#.##"); | |
log.info("Sending progress message: {} %", df.format(d)); | |
} else { | |
log.info("Sending progress message: {}", transfered); | |
} | |
} | |
private synchronized void add(long count) { | |
transfered = transfered + count; | |
} | |
private synchronized long getTransfered() { | |
return transfered; | |
} | |
public synchronized void setTransfered(long transfered) { | |
this.transfered = transfered; | |
} | |
private synchronized void setEnd(boolean isEnd) { | |
this.isEnd = isEnd; | |
} | |
private synchronized boolean isEnd() { | |
return isEnd; | |
} | |
} |
4. 使用连接池
jsch连接池