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;
	

}



猜你喜欢

转载自fall10.iteye.com/blog/2268145