由於項目需要使用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; } } } }