`

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;
	

}



分享到:
评论

相关推荐

    FTP下载工具 局域网下载

    4. **断点续传**:如果下载过程中因网络问题中断,具备断点续传功能的FTP工具可以记录已下载的部分,在恢复连接后继续从上次断点处下载,避免了重头开始。 5. **批量下载**:用户可以一次性添加多个文件或整个目录...

    LeapFTP(FTP客户端) 3.10 汉化版

    3. **高性能传输**:LeapFTP支持断点续传功能,即使在传输过程中遇到网络问题,也能从上次中断的地方继续,避免了重复下载或上传的麻烦。此外,它的传输速度稳定,能充分利用网络带宽,确保大文件快速、安全地传输。...

    一个Windows下载器,使用C++,基于Aria2c开发.zip

    Aria2c是一款轻量级的命令行下载工具,支持HTTP(S)、FTP、SFTP、BitTorrent等多种协议,并且具有断点续传和限速等功能。 首先,我们要理解C++是面向对象的编程语言,它的强大性能和灵活性使得它成为开发系统级和高...

    chrome aria2插件

    Aria2是一款强大的下载管理器,支持HTTP(S)、FTP、SFTP、BitTorrent等多种协议,并且能够实现断点续传和多线程下载,极大地提高了下载效率。 首先,让我们深入了解一下Aria2的核心功能。Aria2是一个命令行工具,...

    FTP 服务器下载文件

    2. 断点续传:记录已下载部分,中断后可以从上次断点继续下载。 3. 重试机制:在网络不稳定时自动重试,保证文件完整下载。 4. 限速控制:避免对服务器造成过大压力,可以设定下载速度上限。 六、安全性考虑 1. ...

    aria2_web下载器

    2. **分块下载与断点续传**:`aria2`可以将大文件分割成多个部分同时下载,并且在下载过程中支持断点续传,即使下载中断,也能从上次中断的地方继续。 3. **限速与优先级设置**:用户可以根据网络状况设定下载速度...

    电脑软件xdown-2.0.3.6 aria2下载.rar

    此外,xdown可能还具备断点续传、计划下载、限速设置等实用功能,以满足不同用户的需求。 接下来,我们转向aria2,这是一款开源的、轻量级的下载管理器。aria2支持HTTP(S)、FTP、SFTP、BitTorrent等多种协议,能...

    轻量级下载程序aria2

    它能够充分利用你的网络带宽,几乎达到理论上的最大下载速度,这是因为aria2采用了多线程、多源下载的技术,将文件从多个源同时下载,从而显著提高了下载效率。无论是HTTP、HTTPS,还是磁力链接(Magnet)或者BT种子...

    ipv6资源下载工具,体验急速的感觉

    3. **断点续传**:如果文件传输中断,可以从上次断点处继续,避免重新下载整个文件。 4. **批量传输**:支持一次性传输多个文件,提高工作效率。 5. **多线程传输**:利用IPv6的多路复用能力,同时处理多个文件传输...

    aria2-1.17.1.tar.gz

    3. **断点续传**:如果下载中断,Aria2可以记住已下载的部分并在稍后恢复下载。 4. **限速和优先级设置**:用户可以根据需要设置下载速度限制,还可以为不同任务设置优先级。 5. **JSON-RPC和Web界面**:Aria2可以...

    aria2-1.19.0.tar.gz

    此外,aria2还具有断点续传和多线程下载的特点,可以有效利用网络资源,提高下载效率。 **主要特点** 1. **多源下载**:aria2可以从多个源同时下载同一个文件,通过分散负载,提高下载速度。 2. **分块下载**:将...

    aria2_1.32.0_win_64

    "aria2 解除限速"这一标签暗示了Aria2的一个关键特性,即它可以通过多源、多线程的下载方式,可能帮助用户绕过某些下载服务的限速策略,提高下载速度。这在处理大型文件或者面对网络限制时尤其有用。 **Aria2的详细...

    FTP源码的实现

    FTP(File Transfer Protocol)是一种基于TCP/IP协议的网络协议,用于在网络上进行文件传输。本项目实现了FTP的客户端...在实际开发中,还可以根据需求添加更多特性,比如支持断点续传、限速控制、文件上传进度显示等。

    aria2 下载器,包含AriaNg-1.3.4,aria2-yaaw

    1. **Aria2特点**: Aria2是一个高性能的下载工具,支持断点续传、多线程、多源下载,能有效地提高下载速度和稳定性。 2. **协议支持**: Aria2可以处理多种下载协议,包括HTTP(S)、FTP、SFTP,以及P2P协议如...

    Aria2 20211207一键启动.zip

    3. **断点续传**:支持暂停和恢复下载,即使在下载过程中出现网络中断,也可以从上次中断的地方继续。 4. **限速控制**:允许用户设定下载速度上限,避免影响其他网络应用。 5. **磁力链接与BT下载**:除了常规URL,...

    Aria2懒人包 省去麻烦的配置

    它支持HTTP(S)、FTP、SFTP、BT(BitTorrent)和磁力链接等多种下载方式,而且具备断点续传、限速控制、多线程下载等功能。Aria2以其高效、稳定和资源占用低的特点,受到了许多用户的喜爱。然而,由于其命令行操作和...

    好用的ftp工具

    1. **多线程传输**:允许同时传输多个文件,提高上传或下载速度。 2. **断点续传**:如果文件传输过程中因网络问题中断,可以从上次断开的地方继续,避免重新传输整个文件。 3. **书签功能**:保存常用的FTP服务器...

    aria2-1.35.0 for mac

    3. **断点续传**:如果下载过程中因网络问题中断,Aria2能够记住已下载的部分并在恢复连接后继续下载,避免了重新开始的麻烦。 4. **限速与调度**:用户可以设置下载和上传的速度限制,以适应不同的网络环境和需求...

    aria2-1.33.0-win-64bit-build1.zip

    4. **断点续传**:如果下载中断,Aria2可以继续从上次停止的地方开始下载。 5. **JSON-RPC和Web界面**:Aria2可以通过JSON-RPC接口进行远程控制,还可以安装Web界面进行图形化管理。 对于开发者而言,Aria2的SDK...

Global site tag (gtag.js) - Google Analytics