`

SFTP下载客户端[单用户多线程、限速、取消、断点续传]

 
阅读更多

采用JSCH API(本例引用了jsch-0.1.52.jar)
官网参考 http://www.jcraft.com/jsch/

1,建立Session,对应一个用户账户,并在无传输线程时自动关闭session

public class SFTPProcessor2 {

	private static final Logger LOGGER = Logger.getLogger(SFTPProcessor2.class);

	private static Session session = null;

	

	public Session getConnect(Map<String, String> serverMap) {
		String ftpHost = serverMap.get(SFTPConstants.SFTP_SERVER_HOST);
		String port = serverMap.get(SFTPConstants.SFTP_SERVER_PORT);
		String ftpUserName = serverMap.get(SFTPConstants.SFTP_SERVER_USERNAME);
		String ftpPassword = serverMap.get(SFTPConstants.SFTP_SERVER_PASSWORD);

		// 默认的端口22 此处我是定义到常量类中;
		int ftpPort = SFTPConstants.SFTP_DEFAULT_PORT;

		// 判断端口号是否为空,如果不为空,则赋值
		if (port != null && !port.equals("")) {
			ftpPort = Integer.valueOf(port);
		}
		JSch jsch = new JSch(); // 创建JSch对象
		// 按照用户名,主机ip,端口获取一个Session对象
		try {
			session = jsch.getSession(ftpUserName, ftpHost, ftpPort);
						
			LOGGER.debug("Session created.");
			if (ftpPassword != null) {
				session.setPassword(ftpPassword); // 设置密码
			}

			// 具体config中需要配置那些内容,请参照sshd服务器的配置文件/etc/ssh/sshd_config的配置
			Properties config = new Properties();

			// 设置不用检查hostKey
			// 如果设置成“yes”,ssh就会自动把计算机的密匙加入“$HOME/.ssh/known_hosts”文件,
			// 并且一旦计算机的密匙发生了变化,就拒绝连接。
			config.put("StrictHostKeyChecking", "no");

			// UseDNS指定,sshd的是否应该看远程主机名,检查解析主机名的远程IP地址映射到相同的IP地址。
			// 默认值是 “yes” 此处是由于我们SFTP服务器的DNS解析有问题,则把UseDNS设置为“no”
			config.put("UseDNS", "no");

			session.setConfig(config); // 为Session对象设置properties
			
			session.setTimeout(SFTPConstants.SFTP_DEFAULT_TIMEOUT); // 设置timeout时候
			session.connect(); // 经由过程Session建树链接
			LOGGER.debug("Session connected.");
			
		} catch (JSchException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return session;
	}
	
/*	public boolean upfile(InputStream is, OutputStream os) throws IOException{
		boolean res = false;
		byte[] b = new byte[1024*1024*100];
		int read;
		if(os!=null){			
			do {
                read = is.read(b, 0, b.length);
                if (read > 0) {
                    os.write(b, 0, read);
                }
                os.flush();
            } while (read >= 0);			
		}		
		return res;
	}*/
	
/*	public void uploadFile(String localFile, String newName,
			String remoteFoldPath) // throws AppBizException
	{
		InputStream input = null;
		OutputStream os = null;
		try {
			File lf = new File(localFile);
			input = new FileInputStream(lf);
			// 改变当前路径到指定路径
			channel.cd(remoteFoldPath);
			long t1 = System.currentTimeMillis();
			//channel.put(input, newName);
			
			os = channel.put(newName
					//, new ProgressMonitor(lf.length()) // 上传时不执行init()方法
					,new ProgressMonitorByBytes(lf.length())
					,ChannelSftp.OVERWRITE) 
					
					;
			
			upfile(input,os);
			
			
			channel.put(localFile
					, newName
					, new ProgressMonitorByBytes()
					, ChannelSftp.OVERWRITE);
			
			
			
			System.out.println("Time elapsed: "  +  (System.currentTimeMillis() - t1) + "(ms)");
		} catch (Exception e) {
			LOGGER.error("Upload file error", e);
			
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					
				}
			}
			if (os != null) {
				try {
					os.close();
				} catch (IOException e) {
					
				}
			}
		}
	}*/



	public static void main(String[] args) throws Exception {
		SFTPProcessor2 ftpUtil = new SFTPProcessor2();
		Map<String, String> ftpServerMap = new HashMap<String, String>();
		ftpServerMap.put((String) SFTPConstants.SFTP_SERVER_HOST, "localhost");
		ftpServerMap.put((String) SFTPConstants.SFTP_SERVER_USERNAME, "name");
		ftpServerMap.put((String) SFTPConstants.SFTP_SERVER_PASSWORD, "password");
		ftpServerMap.put((String) SFTPConstants.SFTP_SERVER_PORT, "22");
		ftpUtil.getConnect(ftpServerMap);
		
		//ftpUtil.uploadFile("e:/eclipse-jee.zip", "eclipse-jee.zip", System.getProperty("file.separator"));		
		
		String rf1 = "eclipse-jee.zip";
		String rp1 = System.getProperty("file.separator")+"d";
		//String rp1 = "";
		String rf2 = "zzzz.zip";
		String rp2 = System.getProperty("file.separator")+"d";
		//String rp2 = "";
		String lf1 = "e:/yyyy.zip";
		String lf2 = "e:/zzzz.zip" ;
					
		
		DownLoadThread d1 = new DownLoadThread(session,rf1,rp1,lf1,
				ftpServerMap.get((String) SFTPConstants.SFTP_SERVER_HOST),
				ftpServerMap.get((String) SFTPConstants.SFTP_SERVER_USERNAME),
				"TRANS100");
		DownLoadThread d2 = new DownLoadThread(session,rf2,rp2,lf2,
				ftpServerMap.get((String) SFTPConstants.SFTP_SERVER_HOST),
				ftpServerMap.get((String) SFTPConstants.SFTP_SERVER_USERNAME),
				"TRANS99");
		final Thread t1 = new Thread(d1);
		final Thread t2 = new Thread(d2);
		t1.start();
		t2.start();

		final List<Thread> lst = new ArrayList<Thread>();
		lst.add(t1);
		lst.add(t2);
		
		//ftpUtil.downloadFile("eclipse-jee.zip", System.getProperty("file.separator")+"d", "e:/zzzz.zip");
		//ftpUtil.downloadFile("snagit.zip", System.getProperty("file.separator")+"d", "e:/test20150608.zip");
		Thread t3 = new Thread(new Runnable(){
			@Override
			public void run() {
				while(true){
					boolean nonlive = true;
					for (int i = 0; i < lst.size(); i++) {
						if(lst.get(i).isAlive()){
							nonlive = false;
							break;
						}
					}
					if( nonlive ){
						System.out.println("No Active transmission, exit!");
						session.disconnect();
						break;
					}
				}
				
			}			
		});
		//t3.setDaemon(true);
		t3.start();
		

	}

}



2,建立通道,多线程下载

public  class DownLoadThread implements Runnable  {
	private static final Logger LOGGER = Logger.getLogger(SFTPProcessor2.class);
	private ChannelSftp channel = null;
	private Session session = null;
	private ProgressMonitorByBytes monitor = null;
	private String remotef = null;
	private String remotep = null;
	private String lf = null;
	private String ftpuser = null;
	private String ftphost = null;
	private String transid = null;
	
	public DownLoadThread(Session ss , String rf ,String rp, String lf ,String host, String user,String tid) {
		this.session = ss;
		//this.monitor = p;
		this.remotef = rf;
		this.remotep = rp;
		this.lf = lf;
		this.ftphost = host;
		this.ftpuser = user;
		this.transid = tid;
	}
	
	@Override
	public void run() {
		
		try {
			channel = getOpenCh(session,ftphost,ftpuser);
			monitor = new ProgressMonitorByBytes(transid,remotef,this.getRemoteFilesize1(channel,remotef,remotep));
			downloadFile(this.remotef,this.remotep,this.lf);
			closeChannel();
			
			//Thread.currentThread().interrupt();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public  ChannelSftp getOpenCh(Session ss ,String ftphost,String ftpusername){
		try {
			LOGGER.debug("Opening SFTP Channel.");
			channel = (ChannelSftp) ss.openChannel("sftp"); // 打开SFTP通道
			channel.connect(); // 建树SFTP通道的连接
			LOGGER.debug("Connected successfully to ftpHost = " + ftphost
					+ ",as ftpUserName = " + ftpusername + ", returning: "
					+ channel);
		} catch (JSchException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return channel;
	}
	
	public void closeChannel() 
	{
		try {
			if (channel != null) {
				channel.disconnect();
			}
		
		} catch (Exception e) {
			LOGGER.error("close sftp error", e);
			// throw new AppBizException(AppExcCodes.CLOSE_FTP_ERROR,
			// "close ftp error.");
		}
	}
	
	public void downloadFile(String remoteFile, String remotePath,String localFile) {
	
		OutputStream output = null;
		File file = null;
		
		try {
			file = new File(localFile);
			
			
			if (!checkFileExist(localFile)) {
				file.createNewFile();
				output = new FileOutputStream(file);
				channel.cd(remotePath);
				//channel.get(remoteFile, output);
				channel.get(remoteFile, localFile
					//, new ProgressMonitor(getRemoteFilesize1(channel,remoteFile,remotePath))
						,monitor
					, ChannelSftp.OVERWRITE);
				
			}else{
				//output = new FileOutputStream(file);
				channel.cd(remotePath);
				
				channel.get(remoteFile, localFile
					//, new ProgressMonitor(getRemoteFilesize1(channel,remoteFile,remotePath))
						,monitor
					, ChannelSftp.RESUME);
				
			}
			
						

		} catch (Exception e) {
			LOGGER.error("Download file error", e);
			
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					
				}
			}
			if (file != null) {
				//file.delete();
			}
		}
	}
	
	private boolean checkFileExist(String localPath) {
		File file = new File(localPath);
		return file.exists();
	}
	
	public long getRemoteFilesize1(ChannelSftp cf , String remoteFile,String remotepath ) {
		
		Object o =  null;
		long s = 0;
		try {
			Vector v =  cf.ls(cf.pwd() + "/" + remotepath + "/" +  remoteFile);
			if(v!=null && v.size() == 1){
				o = v.firstElement();
			}			
			//System.out.println();
			LsEntry  cl =  (LsEntry)o;	
			s = cl.getAttrs().getSize();
			System.out.println(s + "(bytes)");
		} catch (SftpException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return s;
	}
	

}


3,下载进度监控,控制取消,限制速度等

 

public class ProgressMonitorByBytes implements SftpProgressMonitor {

	private long transfered;
	private long filesize;	
	private String remotef;
	private Formatter f = null;
	private long stime;
	private long etime;
	private String transferID ;
	
	public ProgressMonitorByBytes(String transid,String remotefile,
			long totalsize
			) {
		this.filesize = totalsize;
		this.remotef = remotefile;
		this.transferID = transid  ;
	}

	
	public void sendmsg(){
		DecimalFormat df = new DecimalFormat( "#.##");
		String per = df.format(100*(1.0f*transfered/filesize));
        System.out.println("Currently transferred total size: " + transfered + " bytes, percent: " + per + "% [" + remotef + "]" );
        f.format("%1$10s\n","Currently transferred total size: " + transfered + " bytes, percent: " + per + "% [" + remotef + "] " );
	}
	
	@Override
	public boolean count(long count) {
		long now = System.currentTimeMillis();
		long timeelapse = (now - stime);
		boolean cancelCondition = (timeelapse > 10*1000) && "TRANS1000".equals(transferID);
		
		if(transfered != filesize   )   {
			sendmsg();
	        transfered = transfered + count;
	        if(cancelCondition){	//作为取消下载使用,可以取消(暂停下载)
	        	f.format("%1$10s\n","Cancel transfer: [" + remotef + "]");
	        	System.out.printf("%1$10s\n","Cancel transfer: [" + remotef + "]");
	        	return false;
	        }
	        
	        boolean sleepCondition = (1000 * (1.0d/1024) * transfered / timeelapse ) > 4096   ;
	        if(sleepCondition){
	        	try {
					Thread.currentThread().sleep(1000); //作为限速使用,貌似可以限制下载速度
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        }
	        
	        return true;
	        
		}	
		
        
		return false;
	}

	@Override
	public void end() {
		etime = System.currentTimeMillis();
		sendmsg();
		System.out.println("Transferring done. [" + remotef + "]");
		f.format("%1$10s\n", "Transferring done. [" + remotef + "]");
		f.format("%1$10s\n", "Time Elapsed:"+ getTimePassed(etime - stime)  +" [" + remotef + "]");
		f.close();
		
	}
	
	public String getTimePassed(long times){
		String res = "";
		long hours = 0;
		long minutes = 0 ;
		long seconds = 0 ;
		long millseconds = 0;
		hours = times / (1000*60*60);
		minutes = (times - hours * (1000*60*60)) / (1000*60);
		seconds = (times - hours * (1000*60*60) - minutes*1000*60) / 1000;
		millseconds = times - hours * (1000*60*60) - minutes*1000*60 - seconds*1000;
		res = Long.toString(hours, 10)+"小时" + Long.toString(minutes, 10)+"分钟"+ Long.toString(seconds, 10)+"秒"+ Long.toString(millseconds, 10)+"毫秒";
		
		return res;
	}

	/**
	 * @param arg0	1:下载,0:上传
	 * @param arg1	原始文件PATH
	 * @param arg2	目标文件PATH
	 * @param arg3	文件大小
	 * 
	 * */	
	@Override
	public void init(int arg0, String arg1, String arg2, long arg3) {
		stime = System.currentTimeMillis();
		try {
			f = new Formatter(new FileOutputStream("E:/xdownlog.log", true));
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		f.format("%1$10s\n", "Transferring begin. [" + remotef + "]");
		//filesize = arg3;
		System.out.println("Transferring begin. [" + remotef + "]");
		System.out.println("======================");
		System.out.println(arg0);System.out.println(arg1);System.out.println(arg2);System.out.println(arg3);
		System.out.println("======================");
		

	}

}


4,配置用的常量

 

public class SFTPConstants {

	public static final int SFTP_DEFAULT_TIMEOUT = 0;
	public static final Object SFTP_SERVER_HOST = "SFTP_SERVER_HOST";
	public static final Object SFTP_SERVER_PORT = "SFTP_SERVER_PORT";
	public static final Object SFTP_SERVER_USERNAME = "SFTP_SERVER_USERNAME";
	public static final Object SFTP_SERVER_PASSWORD = "SFTP_SERVER_PASSWORD";
	public static final int SFTP_DEFAULT_PORT = 22;
	

}



分享到:
评论

相关推荐

    Java实现多线程下载和断点续传

    1. 把每个下载文件切成若干个块(Block),然后得到一个位图,用来标记每个块的下载情况,并保存到文件里,用于实现断点续传。 2. HTTP Header里增加Range,如果服务器返回Cotent-Range 说明服务器支持文件定位,可以...

    java-多线程下载器(支持断点续传、线程加减)包含源码和可运行jar包 第二版

    2、支持多任务多线程同时下载; 3、每个任务的线程数由用户在新建任务时自定义,缺省为5个线程; 4、任务下载过程中可以点击“线程+”或“线程-”即时增减线程; 5、选择任务,可以在任务信息栏中查看任务下载的信息...

    Linux下的SFTP C语言客户端,包括SFTP下载、上传、list目录和创建目录

    Linux下的SFTP C语言客户端,包括SFTP下载、上传、list目录和创建目录,依赖libssh2库,该库可自行下载编译安装。 全部源代码,可编译和测试。

    FTP客户端软件(可断点续传)

    一个很不错FTP软件,图形化列表,断点续传。

    python 实现断点续传

    自己用python写的断点续传脚本

    SFTP.rar_SFTP客户端_c sftp_sftp c++_sftp 客户端_visual c

    sftp 客户端服务程序 基于 sftp通讯协议~~

    python实现断文件点续传

    此代码基于python实现了服务器/客户端的断点续传,可以作为网络编程中的参考。

    支持多线程的SFTP类代码

    适用多线程的SFTP类,支持代理服务器,是spring服务类,无需修改可直接与spring结合使用。 代码经过大量的并发使用验证,稳定可靠。 依赖的jar包如下: &lt;groupId&gt;com.jcraft&lt;/groupId&gt; &lt;artifactId&gt;...

    vc实现的ftp客户端断点续传

    vc实现的ftp客户端断点续传: __fastcall TMultiFtp::TMultiFtp(TComponent* Owner) : TComponent(Owner) { lock = false; isUseFile = false; runningThreadCnt = 0; stop = false; this-&gt;Owner = Owner; }

    SFTP 客户端工具 适用于window

    SFTP 客户端 SFTP 客户端工具 适用于windowSFTP 客户端工具 适用于window

    WinSCP-SFTP客户端

    Windows环境下使用SSH的开源图形化SFTP客户端。同时支持SCP协议。它的主要功能就是在本地与远程计算机间安全的复制传输文件。 WinSCP传输模式可以选择FTP、SFTP、SCP、WebDAV 4种模式,默认为SFTP模式,我们一般用前...

    Python实现可配置的sftp传输

    该资源为python实现可配置的sftp传输,get和put 配置文件为.ini文件;put和get区分一下源和目的路径,基本配置项即说明如下: [ftp]:ftp基本信息 [common] 公共的配置 如日志信息,传输模式,是否递归,是否删除等 ...

    Qt下基于QFtp/libssh2的ftp/stfp下载客户端源码

    Qt下的ftp/sftp下载客户端,支持断点续传,支持检测下载文件是否存在,支持进度条

    SSH 开源图形化 SFTP 客户端 WinSCP 5.17.9.zip

    WinSCP 是一个 Windows 环境下使用的 SSH 的开源图形化 SFTP 客户端。同时支持 SCP 协议。它的主要功能是在本地与远程计算机间安全地复制文件,并且可以直接编辑文件。 WinSCP 中文绿色版WinSCP 中文绿色版 WinSCP...

    WinSCP图形化SFTP客户端

    WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端。同时支持SCP协议。

    WinSCP(SFTP客户端) v5.13.3中文 免安装版

    WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端。同时支持SCP协议。它的主要功能就是在本地与远程计算机间安全的复制文件。.winscp也可以链接其他系统,比如linux系统

    C语言实现ftp断点续传

    用c语言实现文件的上传和下载...使用ftp协议,实现断点续传功能。文件包中包含完整的源代码。能编译通过。 用c语言实现文件的上传和下载功能;使用ftp协议,实现断点续传功能。文件包中包含完整的源代码。能编译通过。

    C#启动winscp实现SFTP客户端

    在安装目录拷贝该目录下的所有文件到C#可执行程序目录)打开winscp,然后自动连上SFTP服务器,这样就可以直接使用winscp来进行操作了,比如文件上传、下载和删除等,省去自己去写一个sftp客户端,非常方便。...

    winscpSSH的开源图形化SFTP客户端

    WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端。同时支持SCP协议。它的主要功能就是在本地与远程计算机间安全的复制文件。

    C# 文件下载之断点续传实现代码

    注意,本文所说的断点续传特指 HTTP 协议中的断点续传。本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo。 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息。我们可以在一次 HTTP ...

Global site tag (gtag.js) - Google Analytics