http://www.cnblogs.com/longyg/archive/2012/06/25/2556576.htmlhtml
JSch是Java Secure Channel的縮寫。JSch是一個SSH2的純Java實現。它容許你鏈接到一個SSH服務器,而且可使用端口轉發,X11轉發,文件傳輸等,固然你也能夠集成它的功能到你本身的應用程序。java
OVERWRITE | 徹底覆蓋模式,這是JSch的默認文件傳輸模式,即若是目標文件已經存在,傳輸的文件將徹底覆蓋目標文件,產生新的文件。 |
RESUME | 恢復模式,若是文件已經傳輸一部分,這時因爲網絡或其餘任何緣由致使文件傳輸中斷,若是下一次傳輸相同的文件,apache 則會從上一次中斷的地方續傳。安全 |
APPEND | 追加模式,若是目標文件已存在,傳輸的文件將在目標文件後追加。 |
建立ChannelSftp對象 |
編寫一個工具類,根據ip,用戶名及密碼獲得一個SFTP channel對象,即ChannelSftp的實例對象,在應用程序中就可使用該對象來調用SFTP的各類操做方法。服務器
package com.longyg.sftp;import java.util.Map;import java.util.Properties;import org.apache.log4j.Logger;import com.jcraft.jsch.Channel;import com.jcraft.jsch.ChannelSftp;import com.jcraft.jsch.JSch;import com.jcraft.jsch.JSchException;import com.jcraft.jsch.Session;publicclass SFTPChannel { Session session = null; Channel channel = null; privatestaticfinal Logger LOG = Logger.getLogger(SFTPChannel.class.getName()); public ChannelSftp getChannel(Map<String, String> sftpDetails, int timeout) throws JSchException { String ftpHost = sftpDetails.get(SFTPConstants.SFTP_REQ_HOST); String port = sftpDetails.get(SFTPConstants.SFTP_REQ_PORT); String ftpUserName = sftpDetails.get(SFTPConstants.SFTP_REQ_USERNAME); String ftpPassword = sftpDetails.get(SFTPConstants.SFTP_REQ_PASSWORD); int ftpPort = SFTPConstants.SFTP_DEFAULT_PORT; if (port != null && !port.equals("")) { ftpPort = Integer.valueOf(port); } JSch jsch = new JSch(); // 建立JSch對象 session = jsch.getSession(ftpUserName, ftpHost, ftpPort); // 根據用戶名,主機ip,端口獲取一個Session對象 LOG.debug("Session created."); if (ftpPassword != null) { session.setPassword(ftpPassword); // 設置密碼 } Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); // 爲Session對象設置properties session.setTimeout(timeout); // 設置timeout時間 session.connect(); // 經過Session創建連接 LOG.debug("Session connected."); LOG.debug("Opening Channel."); channel = session.openChannel("sftp"); // 打開SFTP通道 channel.connect(); // 創建SFTP通道的鏈接 LOG.debug("Connected successfully to ftpHost = " + ftpHost + ",as ftpUserName = " + ftpUserName + ", returning: " + channel); return (ChannelSftp) channel; } publicvoid closeChannel() throws Exception { if (channel != null) { channel.disconnect(); } if (session != null) { session.disconnect(); } }}
SFTPConstants是一個靜態成員變量類:網絡
package com.longyg.sftp;publicclass SFTPConstants { publicstaticfinal String SFTP_REQ_HOST = "host"; publicstaticfinal String SFTP_REQ_PORT = "port"; publicstaticfinal String SFTP_REQ_USERNAME = "username"; publicstaticfinal String SFTP_REQ_PASSWORD = "password"; publicstaticfinalint SFTP_DEFAULT_PORT = 22; publicstaticfinal String SFTP_REQ_LOC = "location";}
文件上傳 |
實現文件上傳能夠調用ChannelSftp對象的put方法。ChannelSftp中有12個put方法的重載方法:session
public void put(String src, String dst) | 將本地文件名爲src的文件上傳到目標服務器,目標文件名爲dst,若dst爲目錄,則目標文件名將與src文件名相同。ide 採用默認的傳輸模式: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, |
將本地文件名爲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, |
將本地的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開始寫入數據。 |
應用實例:
SFTPTest.java
package com.longyg.sftp;import java.util.HashMap;import java.util.Map;import com.jcraft.jsch.ChannelSftp;publicclass SFTPTest { public SFTPChannel getSFTPChannel() { returnnew SFTPChannel(); } /** * @param args * @throws Exception */publicstaticvoid main(String[] args) throws Exception { SFTPTest test = new SFTPTest(); Map<String, String> sftpDetails = new HashMap<String, String>(); // 設置主機ip,端口,用戶名,密碼 sftpDetails.put(SFTPConstants.SFTP_REQ_HOST, "10.9.167.55"); sftpDetails.put(SFTPConstants.SFTP_REQ_USERNAME, "root"); sftpDetails.put(SFTPConstants.SFTP_REQ_PASSWORD, "arthur"); sftpDetails.put(SFTPConstants.SFTP_REQ_PORT, "22"); String src = "D:\\DevSoft\\HB-SnagIt1001.rar"; // 本地文件名 String dst = "/home/omc/ylong/sftp/HB-SnagIt1001.rar"; // 目標文件名 SFTPChannel channel = test.getSFTPChannel(); ChannelSftp chSftp = channel.getChannel(sftpDetails, 60000); /** * 代碼段1 OutputStream out = chSftp.put(dst, ChannelSftp.OVERWRITE); // 使用OVERWRITE模式 byte[] buff = new byte[1024 * 256]; // 設定每次傳輸的數據塊大小爲256KB int read; if (out != null) { System.out.println("Start to read input stream"); InputStream is = new FileInputStream(src); do { read = is.read(buff, 0, buff.length); if (read > 0) { out.write(buff, 0, read); } out.flush(); } while (read >= 0); System.out.println("input stream read done."); } **/ chSftp.put(src, dst, ChannelSftp.OVERWRITE); // 代碼段2 // chSftp.put(new FileInputStream(src), dst, ChannelSftp.OVERWRITE); // 代碼段3 chSftp.quit(); channel.closeChannel(); }}
注:請分別將代碼段1,代碼段2,代碼段3取消註釋,運行程序來進行測試。這三段代碼分別演示瞭如何使用JSch的不一樣的put方法來進行文件上傳。
代碼段1:採用向put方法返回的輸出流中寫入數據的方式來傳輸文件。 須要由程序來決定寫入什麼樣的數據,這裏是將本地文件的輸入流寫入輸出流。採用這種方式的好處是,能夠自行設定每次寫入輸出流的數據塊大小,如本示例中的語句:
byte[] buff = newbyte[1024 * 256]; // 設定每次傳輸的數據塊大小爲256KB
代碼段2:直接將本地文件名爲src的文件上傳到目標服務器,目標文件名爲dst。(注:使用這個方法時,dst能夠是目錄,當dst是目錄時,上傳後的目標文件名將與src文件名相同)
代碼段3:將本地文件名爲src的文件輸入流上傳到目標服務器,目標文件名爲dst。
這三段代碼實現的功能是同樣的,都是將本地的文件src上傳到了服務器的dst文件。使用時可根據具體狀況選擇使用哪一種實現方式。
監控傳輸進度 |
從前面的介紹中知道,JSch支持在文件傳輸時對傳輸進度的監控。能夠實現JSch提供的SftpProgressMonitor接口來完成這個功能。
SftpProgressMonitor接口類的定義爲:
package com.jcraft.jsch;publicinterface SftpProgressMonitor{ publicstaticfinalint PUT=0; publicstaticfinalint GET=1; void init(int op, String src, String dest, long max); boolean count(long count); void end();}
init(): 當文件開始傳輸時,調用init方法。
count(): 當每次傳輸了一個數據塊後,調用count方法,count方法的參數爲這一次傳輸的數據塊大小。
end(): 當傳輸結束時,調用end方法。
下面是一個簡單的實現:
MyProgressMonitor.java
package com.longyg.sftp;import com.jcraft.jsch.SftpProgressMonitor;publicclass MyProgressMonitor implements SftpProgressMonitor { privatelong transfered; @Override publicboolean count(long count) { transfered = transfered + count; System.out.println("Currently transferred total size: " + transfered + " bytes"); returntrue; } @Override publicvoid end() { System.out.println("Transferring done."); } @Override publicvoid init(int op, String src, String dest, long max) { System.out.println("Transferring begin."); }}
此時若是改變SFTPTest main方法裏調用的put方法,便可實現監控傳輸進度:
SFTPTest.java
package com.longyg.sftp;import java.util.HashMap;import java.util.Map;import com.jcraft.jsch.ChannelSftp;publicclass SFTPTest { public SFTPChannel getSFTPChannel() { returnnew SFTPChannel(); } /** * @param args * @throws Exception */publicstaticvoid main(String[] args) throws Exception { SFTPTest test = new SFTPTest(); Map<String, String> sftpDetails = new HashMap<String, String>(); // 設置主機ip,端口,用戶名,密碼 sftpDetails.put(SFTPConstants.SFTP_REQ_HOST, "10.9.167.55"); sftpDetails.put(SFTPConstants.SFTP_REQ_USERNAME, "root"); sftpDetails.put(SFTPConstants.SFTP_REQ_PASSWORD, "arthur"); sftpDetails.put(SFTPConstants.SFTP_REQ_PORT, "22"); String src = "D:\\DevSoft\\HB-SnagIt1001.rar"; // 本地文件名 String dst = "/home/omc/ylong/sftp/HB-SnagIt1001.rar"; // 目標文件名 SFTPChannel channel = test.getSFTPChannel(); ChannelSftp chSftp = channel.getChannel(sftpDetails, 60000); /** * 代碼段1 OutputStream out = chSftp.put(dst, new MyProgressMonitor(), ChannelSftp.OVERWRITE); // 使用OVERWRITE模式 byte[] buff = new byte[1024 * 256]; // 設定每次傳輸的數據塊大小爲256KB int read; if (out != null) { System.out.println("Start to read input stream"); InputStream is = new FileInputStream(src); do { read = is.read(buff, 0, buff.length); if (read > 0) { out.write(buff, 0, read); } out.flush(); } while (read >= 0); System.out.println("input stream read done."); } **/ chSftp.put(src, dst, new MyProgressMonitor(), ChannelSftp.OVERWRITE); // 代碼段2 // chSftp.put(new FileInputStream(src), dst, new MyProgressMonitor(), ChannelSftp.OVERWRITE); // 代碼段3 chSftp.quit(); channel.closeChannel(); }}
注意修改的內容僅僅是put方法,在put方法中增長了SftpProgressMonitor的實現類對象monitor做爲參數,即添加了對進度監控的支持。
運行,輸出結果以下:
Start to read input streamCurrently transferred total size: 262144 bytesCurrently transferred total size: 524288 bytesCurrently transferred total size: 786432 bytesCurrently transferred total size: 1048576 bytesCurrently transferred total size: 1310720 bytesCurrently transferred total size: 1572864 bytesCurrently transferred total size: 1835008 bytesCurrently transferred total size: 2097152 bytesCurrently transferred total size: 2359296 bytesCurrently transferred total size: 2621440 bytesCurrently transferred total size: 2883584 bytesCurrently transferred total size: 3145728 bytesCurrently transferred total size: 3407872 bytesCurrently transferred total size: 3670016 bytesCurrently transferred total size: 3848374 bytesinput stream read done.
固然這個SftpProgressMonitor的實現實在太簡單。JSch每次傳輸一個數據塊,就會調用count方法來實現主動進度通知。
如今咱們但願每間隔必定的時間才獲取一下文件傳輸的進度。。。看看下面的SftpProgressMonitor實現:
package com.longyg.sftp;import java.text.DecimalFormat;import java.util.Timer;import java.util.TimerTask;import com.jcraft.jsch.SftpProgressMonitor;publicclass FileProgressMonitor extends TimerTask implements SftpProgressMonitor { privatelong progressInterval = 5 * 1000; // 默認間隔時間爲5秒privateboolean isEnd = false; // 記錄傳輸是否結束privatelong transfered; // 記錄已傳輸的數據總大小privatelong fileSize; // 記錄文件總大小private Timer timer; // 定時器對象privateboolean isScheduled = false; // 記錄是否已啓動timer記時器public FileProgressMonitor(long fileSize) { this.fileSize = fileSize; } @Override publicvoid run() { if (!isEnd()) { // 判斷傳輸是否已結束 System.out.println("Transfering is in progress."); long transfered = getTransfered(); if (transfered != fileSize) { // 判斷當前已傳輸數據大小是否等於文件總大小 System.out.println("Current transfered: " + transfered + " bytes"); sendProgressMessage(transfered); } else { System.out.println("File transfering is done."); setEnd(true); // 若是當前已傳輸數據大小等於文件總大小,說明已完成,設置end } } else { System.out.println("Transfering done. Cancel timer."); stop(); // 若是傳輸結束,中止timer記時器return; } } publicvoid stop() { System.out.println("Try to stop progress monitor."); if (timer != null) { timer.cancel(); timer.purge(); timer = null; isScheduled = false; } System.out.println("Progress monitor stoped."); } publicvoid start() { System.out.println("Try to start progress monitor."); if (timer == null) { timer = new Timer(); } timer.schedule(this, 1000, progressInterval); isScheduled = true; System.out.println("Progress monitor started."); } /** * 打印progress信息 * @param transfered */privatevoid sendProgressMessage(long transfered) { if (fileSize != 0) { double d = ((double)transfered * 100)/(double)fileSize; DecimalFormat df = new DecimalFormat( "#.##"); System.out.println("Sending progress message: " + df.format(d) + "%"); } else { System.out.println("Sending progress message: " + transfered); } } /** * 實現了SftpProgressMonitor接口的count方法 */publicboolean count(long count) { if (isEnd()) returnfalse; if (!isScheduled) { start(); } add(count); returntrue; } /** * 實現了SftpProgressMonitor接口的end方法 */publicvoid end() { setEnd(true); System.out.println("transfering end."); } privatesynchronizedvoid add(long count) { transfered = transfered + count; } privatesynchronizedlong getTransfered() { return transfered; } publicsynchronizedvoid setTransfered(long transfered) { this.transfered = transfered; } privatesynchronizedvoid setEnd(boolean isEnd) { this.isEnd = isEnd; } privatesynchronizedboolean isEnd() { return isEnd; } publicvoid init(int op, String src, String dest, long max) { // Not used for putting InputStream }}
再次修改SFTPTest main方法裏的put方法,改成使用新的SftpProgressMonitor的實現類對象monitor做爲參數,注意新的monitor對象的構造函數須要傳入文件大小做爲參數:
package com.longyg.sftp;import java.io.File;import java.util.HashMap;import java.util.Map;import com.jcraft.jsch.ChannelSftp;publicclass SFTPTest { public SFTPChannel getSFTPChannel() { returnnew SFTPChannel(); } /** * @param args * @throws Exception */publicstaticvoid main(String[] args) throws Exception { SFTPTest test = new SFTPTest(); Map<String, String> sftpDetails = new HashMap<String, String>(); // 設置主機ip,端口,用戶名,密碼 sftpDetails.put(SFTPConstants.SFTP_REQ_HOST, "10.9.167.55"); sftpDetails.put(SFTPConstants.SFTP_REQ_USERNAME, "root"); sftpDetails.put(SFTPConstants.SFTP_REQ_PASSWORD, "arthur"); sftpDetails.put(SFTPConstants.SFTP_REQ_PORT, "22"); String src = "D:\\DevSoft\\HB-SnagIt1001.rar"; // 本地文件名 String dst = "/home/omc/ylong/sftp/HB-SnagIt1001.rar"; // 目標文件名 SFTPChannel channel = test.getSFTPChannel(); ChannelSftp chSftp = channel.getChannel(sftpDetails, 60000); File file = new File(src); long fileSize = file.length(); /** * 代碼段1 OutputStream out = chSftp.put(dst, new FileProgressMonitor(fileSize), ChannelSftp.OVERWRITE); // 使用OVERWRITE模式 byte[] buff = new byte[1024 * 256]; // 設定每次傳輸的數據塊大小爲256KB int read; if (out != null) { System.out.println("Start to read input stream"); InputStream is = new FileInputStream(src); do { read = is.read(buff, 0, buff.length); if (read > 0) { out.write(buff, 0, read); } out.flush(); } while (read >= 0); System.out.println("input stream read done."); } **/ chSftp.put(src, dst, new FileProgressMonitor(fileSize), ChannelSftp.OVERWRITE); // 代碼段2 // chSftp.put(new FileInputStream(src), dst, new FileProgressMonitor(fileSize), ChannelSftp.OVERWRITE); // 代碼段3 chSftp.quit(); channel.closeChannel(); }}
再次運行,結果輸出爲:
Try to start progress monitor.Progress monitor started.Transfering is in progress.Current transfered: 98019 bytesSending progress message: 2.55%Transfering is in progress.Current transfered: 751479 bytesSending progress message: 19.53%Transfering is in progress.Current transfered: 1078209 bytesSending progress message: 28.02%......Transfering is in progress.Current transfered: 3430665 bytesSending progress message: 89.15%transfering end.Transfering done. Cancel timer.Try to stop progress monitor.Progress monitor stoped.
如今,程序每隔5秒鐘纔會打印一下進度信息。能夠修改FileProgressMonitor類裏的progressInterval變量的值,來修改默認的間隔時間。