由於項目需要使用java來linux進行管理,近一番查找,發現第三方jar包 jsch 可以輕松實現對linux的管理,(相關文檔及例子請訪問官網www.jcraft.com),故引進。
在網上搜索了一些資料參考並修改(資料來源地址一下子找不到了,有發現的請提醒加上),創建一個工具類,可以實現對linux上的基本操作及系統上文件的上傳和下載。
代碼如下:
/**
* @description 用來創建與 linux 交互的會話,操作文件和執行 操作 命令
* @date: 2016/7/25
* @author: gongtao
*/
public class LinuxConnetionHelper {
private static final org.slf4j.Logger log = LoggerFactory.getLogger(LinuxConnetionHelper.class);
private static final int TIME_OUT = 5*60*1000; //設置超時為5分鍾
private static final Map<String,Session> cache = new HashMap<>(); //session緩存
public static SessionMonitor sessionMonitor;
/**
* 創建 連接,需手動關閉
* @param host
* @param userName
* @param password
* @param port
* @throws JSchException
*/
public static Session connect(String host,String userName,String password,int port) throws JSchException {
//創建對象
JSch jsch = new JSch();
//創建會話
Session session = jsch.getSession(userName,host, port);
//輸入密碼
session.setPassword(password);
//配置信息
Properties config = new Properties();
//設置不用檢查hostKey
//如果設置成“yes”,ssh就不會自動把計算機的密匙加入“$HOME/.ssh/known_hosts”文件,
//並且一旦計算機的密匙發生了變化,就拒絕連接。
config.setProperty("StrictHostKeyChecking", "no");
// //默認值是 “yes” 此處是由於我們SFTP服務器的DNS解析有問題,則把UseDNS設置為“no”
// config.put("UseDNS", "no");
session.setConfig(config);
//過期時間
session.setTimeout(TIME_OUT);
//建立連接
session.connect();
return session;
}
/**
* 創建 連接,無需手動關閉
* @param host
* @param userName
* @param password
* @param port
* @throws JSchException
*/
public static Session longConnect(String host,String userName,String password,int port) throws JSchException {
String key = host + userName + password + port;
Session session = cache.get(key);
if (session == null){
//創建對象
JSch jsch = new JSch();
//創建會話
session = jsch.getSession(userName,host, port);
//輸入密碼
session.setPassword(password);
//配置信息
Properties config = new Properties();
//設置不用檢查hostKey
//如果設置成“yes”,ssh就不會自動把計算機的密匙加入“$HOME/.ssh/known_hosts”文件,
//並且一旦計算機的密匙發生了變化,就拒絕連接。
config.setProperty("StrictHostKeyChecking", "no");
// //默認值是 “yes” 此處是由於我們SFTP服務器的DNS解析有問題,則把UseDNS設置為“no”
// config.put("UseDNS", "no");
session.setConfig(config);
//過期時間
//session.setTimeout(TIME_OUT);
//建立連接,此時會在linux上新建一個進程,timeout 並不會結束進程,只有調用disconnect()才會結束此進程
session.connect();
cache.put(key,session);
}else{
//判斷session是否失效
if (testSessionIsDown(key)){
//session is down
//session 失去連接則清除
closeLongSessionByKey(key);
//重新生成session
session = longConnect(host, userName, password, port);
}
}
//創建定時器
createSessionMonitor();
return session;
}
/**
* 銷毀 session
* @param session
*/
public static void close(Session session){
if (session != null){
session.disconnect();
}
}
/**
* 測試session是否失效
* @param key
* @return
*/
public static boolean testSessionIsDown(String key){
Session session = cache.get(key);
if (session == null){
return true;
}
ChannelExec channelExec = null;
try {
channelExec = openChannelExec(session);
channelExec.setCommand("true");
channelExec.connect();
return false;
}catch (Throwable e){
//session is down
return true;
}finally {
if (channelExec != null){
channelExec.disconnect();
}
}
}
/**
* 銷毀 session
* @param key
*/
public static synchronized void closeLongSessionByKey(String key){
Session session = cache.get(key);
if (session != null){
session.disconnect();
cache.remove(key);
}
}
/**
* 銷毀 session
* @param session
*/
public static void closeLongSessionBySession(Session session){
Iterator iterator = cache.keySet().iterator();
while (iterator.hasNext()){
String key = (String)iterator.next();
Session oldSession = cache.get(key);
if (session == oldSession){
session.disconnect();
cache.remove(key);
return;
}
}
}
/**
* 創建一個 sftp 通道並建立連接
* @param session
* @return
* @throws Exception
*/
public static ChannelSftp openChannelSftp(Session session) throws Exception
{
ChannelSftp channelSftp = (ChannelSftp)session.openChannel("sftp");
channelSftp.connect();
return channelSftp;
}
/**
* 關閉 sftp 通道
* @param channelSftp
* @throws Exception
*/
public static void closeChannelSftp(ChannelSftp channelSftp)
{
if (channelSftp != null){
channelSftp.disconnect();
}
}
/**
* 下載文件
* @param remoteFile
* 遠程服務器的文件路徑
* @param localPath
* 需要保存文件的本地路徑
* @throws IOException
* @throws SftpException
*/
public static void downloadFile(Session session , String remoteFile, String localPath) throws Exception {
ChannelSftp channelSftp = openChannelSftp(session);
try {
String remoteFilePath = remoteFile.substring(0, remoteFile.lastIndexOf("/"));
String remoteFileName = remoteFile.substring(remoteFile.lastIndexOf("/") + 1,remoteFile.length());
if(localPath.charAt(localPath.length() - 1) != '/'){
localPath += '/';
}
File file = new File(localPath + remoteFileName);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
OutputStream output = new FileOutputStream(file);
try {
channelSftp.cd(remoteFilePath);
log.info("遠程服務器路徑:" + remoteFilePath);
log.info("本地下載路徑:" + localPath + remoteFileName);
SftpATTRS attrs = channelSftp.lstat(remoteFile);
channelSftp.get(remoteFile, output, new FileSftpProgressMonitor(attrs.getSize()));
}catch (Exception e){
throw e;
}finally {
output.flush();
output.close();
}
}catch (Exception e){
throw e;
}finally {
closeChannelSftp(channelSftp);
}
}
/**
* 上傳文件
* @param localFile
* 本地文件路徑
* @param remotePath
* 遠程服務器路徑
* @throws IOException
* @throws SftpException
*/
public static void uploadFile(Session session,String localFile,String remotePath) throws Exception {
ChannelSftp channelSftp = openChannelSftp(session);
String remoteFileName = localFile.substring(localFile.lastIndexOf("/") + 1, localFile.length());
File file = new File(localFile);
final InputStream input = new FileInputStream(file);
try {
channelSftp.cd(remotePath);
}catch (SftpException e){
String tempPath = null;
try {
tempPath = remotePath.substring(0, remotePath.lastIndexOf("/"));
channelSftp.cd(tempPath);
}catch (SftpException e1){
channelSftp.mkdir(tempPath);
}
channelSftp.mkdir(remotePath);
channelSftp.cd(remotePath);
}
log.info("遠程服務器路徑:" + remotePath);
log.info("本地上傳路徑:" + localFile);
try {
channelSftp.put(input, remoteFileName, new FileSftpProgressMonitor(file.length()));
}catch (Exception e){
throw e;
}finally {
input.close();
closeChannelSftp(channelSftp);
}
}
/**
* 文件上傳
* @param session
* @param inputStream
* @param fileName
* @param remotePath
* @throws Exception
*/
public static void uploadFile(Session session,InputStream inputStream,String fileName,String remotePath) throws Exception {
ChannelSftp channelSftp = openChannelSftp(session);
channelSftp.cd(remotePath);
log.info("遠程服務器路徑:" + remotePath);
try {
channelSftp.put(inputStream, fileName,new FileSftpProgressMonitor(inputStream.available()));
}catch (Exception e){
throw e;
}finally {
inputStream.close();
closeChannelSftp(channelSftp);
}
}
/**
* 獲取遠程服務器文件列表
* @param session
* @param remotePath
* 遠程服務器路徑
* @return
* @throws SftpException
*/
public static Vector listFiles(Session session,String remotePath) throws Exception {
ChannelSftp channelSftp = openChannelSftp(session);
try {
Vector vector = channelSftp.ls(remotePath);
return vector;
}catch (Exception e){
throw e;
}finally {
closeChannelSftp(channelSftp);
}
}
/**
* 刪除文件
* @param session
* @param remotePath
* @param fileName
* @throws Exception
*/
public static void removeFile(Session session,String remotePath,String fileName) throws Exception{
ChannelSftp channelSftp = openChannelSftp(session);
try {
channelSftp.cd(remotePath);
channelSftp.rm(fileName);
}catch (Exception e){
throw e;
}finally {
closeChannelSftp(channelSftp);
}
}
/**
* 刪除文件夾
* @param session
* @param remotePath
* @throws Exception
*/
public static void removeDir(Session session,String remotePath) throws Exception{
ChannelSftp channelSftp = openChannelSftp(session);
try {
if (remotePath.lastIndexOf("/") == remotePath.length() - 1){
remotePath = remotePath.substring(0,remotePath.length() - 1);
}
String parentDir = remotePath.substring(0,remotePath.lastIndexOf("/") + 1);
String rmDir = remotePath.substring(remotePath.lastIndexOf("/") + 1,remotePath.length());
channelSftp.cd(parentDir);
channelSftp.rmdir(rmDir);
}catch (Exception e){
throw e;
}finally {
closeChannelSftp(channelSftp);
}
}
/**
* 新建一個 exec 通道
* @param session
* @return
* @throws JSchException
*/
public static ChannelExec openChannelExec(Session session) throws JSchException {
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
return channelExec;
}
/**
* 關閉 exec 通道
* @param channelExec
*/
public static void closeChannelExec(ChannelExec channelExec){
if (channelExec != null){
channelExec.disconnect();
}
}
/**
* 執行 腳本
* @param session
* @param cmd
* 執行 .sh 腳本
* @param charset
* 字符格式
* @return
* @throws IOException
* @throws JSchException
*/
public static String[] execCmd(Session session,String cmd,String charset) throws Exception{
//打開通道
ChannelExec channelExec = openChannelExec(session);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream error = new ByteArrayOutputStream();
channelExec.setCommand(cmd);
channelExec.setOutputStream(out);
channelExec.setErrStream(error);
channelExec.connect();
//確保能夠執行完成及響應所有數據
Thread.sleep(10000);
String[] msg = new String[2];
msg[0] = new String(out.toByteArray(),charset);
msg[1] = new String(error.toByteArray(),charset);
out.close();
error.close();
//關閉通道
closeChannelExec(channelExec);
return msg;
}
/**
* 創建一個交互式的 shell 通道
* @param session
* @return
* @throws JSchException
*/
public static ChannelShell openChannelShell(Session session) throws JSchException{
ChannelShell channelShell = (ChannelShell)session.openChannel("shell");
return channelShell;
}
/**
* 關閉 shell 通道
* @param channelShell
*/
public static void closeChannelShell(ChannelShell channelShell){
if (channelShell != null){
channelShell.disconnect();
}
}
/**
* 執行命令
* @param cmds
* 命令參數
* @param session
* @param timeout
* 連接超時時間
* @param sleepTimeout
* 線程等待時間
* @return
* @throws Exception
*/
public static String execShellCmd(String[] cmds,Session session,int timeout,int sleepTimeout) throws Exception {
//打開通道
ChannelShell channelShell = openChannelShell(session);
//設置輸入輸出流
PipedOutputStream pipedOut = new PipedOutputStream();
ByteArrayOutputStream errorOut = new ByteArrayOutputStream();
channelShell.setInputStream(new PipedInputStream(pipedOut));
channelShell.setOutputStream(errorOut);
channelShell.connect(timeout);
for (String cmd : cmds){
pipedOut.write(cmd.getBytes("UTF-8"));
//線程休眠,保證執行命令后能夠及時返回響應數據
Thread.sleep(sleepTimeout);
}
String msg = new String(errorOut.toByteArray(),"UTF-8");
log.info(msg);
pipedOut.close();
errorOut.close();
//關閉通道
closeChannelShell(channelShell);
return msg;
}
/**
* 創建定時器,清除timeout 的 session 連接
*/
public static void createSessionMonitor(){
if (sessionMonitor == null){
synchronized (SessionMonitor.class){
if (sessionMonitor == null){
//定時器,定時清除失效的session
sessionMonitor = new SessionMonitor();
sessionMonitor.start();
}
}
}
}
/**
* 監控文件傳輸
*/
static class FileSftpProgressMonitor extends TimerTask implements SftpProgressMonitor{
private long progressInterval = 5 * 1000; // 默認間隔時候為5秒
private boolean isEnd = false; // 記錄傳輸是否停止
private long transfered; // 記錄已傳輸的數據總大小
private long fileSize; // 記錄文件總大小
private Timer timer; // 定時器對象
private boolean isScheduled = false; // 記錄是否已啟動timer定時器
private NumberFormat df = NumberFormat.getInstance(); //格式化
public FileSftpProgressMonitor(long fileSize){
this.fileSize = fileSize;
}
@Override
public void run() {
if (!isEnd()){
long transfered = getTransfered();
if (transfered != fileSize){
log.info("Current transfered: " + transfered + " bytes");
sendProgressMessage(transfered);
}else{
log.info("transfered end.");
setIsEnd(true);
}
}else {
log.info("Transfering done. Cancel timer.");
stop(); // 若是傳輸停止,停止timer記時器
}
}
/**
* 定時器關閉
*/
public void stop() {
log.info("Try to stop progress monitor.");
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
isScheduled = false;
}
log.info("Progress monitor stoped.");
}
/**
* 定時器啟動
*/
public void start() {
log.info("Try to start progress monitor.");
if (timer == null) {
timer = new Timer();
}
timer.schedule(this, 1000, progressInterval);
isScheduled = true;
log.info("Progress monitor started.");
}
/**
* 傳輸進度
* @param transfered
*/
private void sendProgressMessage(long transfered) {
if (fileSize != 0) {
double d = ((double)transfered * 100)/(double)fileSize;
log.info("Sending progress message: " + df.format(d) + "%");
} else {
log.info("Sending progress message: " + transfered);
}
}
@Override
public void init(int i, String s, String s1, long l) {
log.info("transfering start.");
}
@Override
public boolean count(long l) {
if (isEnd()){
return false;
}
if (!getIsScheduled()){
start();
}
add(l);
return true;
}
@Override
public void end() {
setIsEnd(false);
log.info("transfering end.");
}
private synchronized void add(long count) {
transfered = transfered + count;
}
public synchronized boolean isEnd() {
return isEnd;
}
public synchronized void setIsEnd(boolean isEnd) {
this.isEnd = isEnd;
}
public synchronized long getTransfered() {
return transfered;
}
public synchronized void setTransfered(long transfered) {
this.transfered = transfered;
}
public synchronized boolean getIsScheduled() {
return isScheduled;
}
public synchronized void setIsScheduled(boolean isScheduled) {
this.isScheduled = isScheduled;
}
}
/**
* 定時器,定時清除失效的session
*/
static class SessionMonitor extends TimerTask{
private Timer timer; // 定時器對象
private long progressInterval = 30 * 1000; // 默認間隔時候為30秒
@Override
public void run() {
if (!cache.isEmpty()){
Iterator iterator = cache.keySet().iterator();
while (iterator.hasNext()){
String key = (String)iterator.next();
//清除失效session
if (testSessionIsDown(key)){
closeLongSessionByKey(key);
}
}
}
}
public void start(){
if (timer == null){
timer = new Timer();
}
timer.schedule(this,1000,progressInterval);
}
public void stop(){
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
}
}
}
