⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 download.java

📁 仿迅雷下载器,http下载,多线程.多任务
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
						}
						Thread.currentThread().interrupt();//中断线程,跳出循环
						System.out.println("计时线程中断."+Thread.currentThread().isInterrupted());
						return;
					}
				}
			}
		}
		
		/**
		 * 计算下载任务的进度.
		 *
		 */
		private void getProgress()
		{
			this.downLoadSchedule= this.interceptFolat((point/(1024f*1024))+readTotal/(1024f*1024))+"M";
		}

		
		/**
		 * 通过断点值得到下载任务进度.公有方法,被外部调用.
		 * @param point
		 * @return
		 */
		public String getProgress(long point)
		{
			return this.interceptFolat(point/(1024f*1024))+"M";
		}
		
		
		/**
		 * 格式化float,保留两个小数点.
		 * @param f
		 * @return
		 */
		private float interceptFolat(float f)
		{
			return new BigDecimal(f).setScale(2, BigDecimal.ROUND_HALF_DOWN).floatValue();
		}
		
		
		/**
		 * 格式化时间:(0:0:0)
		 * @param f
		 * @return
		 */
		public  String getTime(float f)
		{
			int i=(int)f;
			//小时
			int hour=i/3600;
			//分
			int min=(i%3600)/60;
			//秒
			int sec=(i%3600)%60;
	
			if(hour>99)
			{
				hour=99;
			}
			return hour+":"+min+":"+sec;
		}
		
	}
	
	
	
	
	/**
	 * 同步方法,有任务完成时调用.传递一个线程锁作参数.
	 * @param downLoad
	 */
	private synchronized  void saveTaskEnd(DownLoad downLoad)
	{
		JTable taskEndTable=SaveRunTime.getTASKEND_TABLE();
		
		taskEndTable.setValueAt(new XDownTable().getImageIcon("/image/Ok.png"), TASK_COMPLETE, 0);
		taskEndTable.setValueAt(downLoad.saveFileName, TASK_COMPLETE, 1);
		//下载进度.
		taskEndTable.setValueAt(new CounterThread().interceptFolat(downLoad.fileLength/(1024*1024f))+"M", TASK_COMPLETE, 2);
		
		taskEndTable.setValueAt("--", TASK_COMPLETE, 3);
		
		taskEndTable.setValueAt("--", TASK_COMPLETE, 4);
		taskEndTable.setValueAt(new CounterThread().getTime(downLoad.second+0f), TASK_COMPLETE, 5);
		taskEndTable.setValueAt(downLoad.fileType, TASK_COMPLETE, 6);
		TASK_COMPLETE++;//静态变量.
	}
	
	 
	
	/**
	 * 用于改造从URL得到的文件名,如/music/c.mp3 ,只取c.mp3
	 * @param fileName
	 * @return
	 */
	public String interceptURL(String fileName)
	{
		return new StringBuilder(fileName).delete(0, fileName.lastIndexOf("/")+1).toString();
	}
	
	
	
	/**
	 * 控制线程运行状态时调用.
	 * @param downLoadSign
	 */
	public  void setDownLoadSign(int downLoadSign)
	{
		this.downLoadSign=downLoadSign;
	}
	
	
	/**
	 *返回线程的运行状态. 
	 * @return
	 */
	public int getDownLoadSign()
	{
		return this.downLoadSign;
	}
	
	
	/**
	 * 返回保存的文件名.
	 * @return
	 */
	public String getDownLoadFileName()	
	{
		return this.saveFileName;
	}
	
	/**
	 * 返回保存的文件路径.
	 * @return
	 */
	public String getDownLoadFileDirectory()
	{
		return this.saveDirectory;
	}
	
	
	/**
	 * 有任务完成,或删除任务时调用.传递行索引值.判断此索引行周围的线程运行状态.作出处理.
	 * @param row
	 */
	public synchronized  void taskEnd(int row)  
	{
		
		List list=SaveRunTime.getLIST();
		if(row==(list.size()-1))//如果最后一个任务完成.
		{
			//直接清空行.
			removeLock(row);//删除锁
			setLastRowNull();//先删除锁,再清空最后一行.
			return;
		}
		else
		{
			setRowIndexInfo(row);//身后还有任务.
		}
	}
	
	
	
	/**
	 * 返回给定行的线程对象.只被setRowIndexInfo()方法调用.
	 * @param row
	 * @return
	 */
	private DownLoad getRowIndexDownLoadObj(int row)
	{
		return (DownLoad)SaveRunTime.getLIST().get(row);
	}
	
	
	/**
	 * 有任务完成,或删除任务时由taskEnd()方法调用.
	 * @param row
	 */
	private synchronized void setRowIndexInfo(int row)
	{
		int rowFirst=row;
		DownLoad downLoad=null;
		JTable DOWNTABLE=SaveRunTime.getDOWN_TABLE();
		for(;row<SaveRunTime.getLIST().size()-1;row++)
		{
			downLoad=getRowIndexDownLoadObj(row+1);//紧挨着身后的一行.
			
			if(downLoad.downLoadSign==1)//一个正在运行的线程.
			{
				//正在运行图片.
				DOWNTABLE.setValueAt(new XDownTable().getImageIcon("/image/ing.png"), row, 0);
				DOWNTABLE.setValueAt("",row,3);//速度
				DOWNTABLE.setValueAt("",row,4);//剩余时间
			}
			else if(downLoad.downLoadSign==0||downLoad.downLoadSign==-3)//线程在等待状态
			{
				//暂停图片.
				DOWNTABLE.setValueAt(new XDownTable().getImageIcon("/image/dpause.png"), row, 0);
				DOWNTABLE.setValueAt("--",row,3);//速度
				DOWNTABLE.setValueAt("--",row,4);//剩余时间
			}
			else if(downLoad.downLoadSign==-1)//任务停止中.
			{
				//链接中断图片.
				DOWNTABLE.setValueAt(new XDownTable().getImageIcon("/image/die.png"), row, 0);
				DOWNTABLE.setValueAt("--",row,3);//速度
				DOWNTABLE.setValueAt("--",row,4);//剩余时间
			}//将下一行的内容设置向上移动一行
			DOWNTABLE.setValueAt(DOWNTABLE.getValueAt(row+1, 1), row, 1);//文件名.
			DOWNTABLE.setValueAt(DOWNTABLE.getValueAt(row+1, 2), row, 2);//下载进度表.
			DOWNTABLE.setValueAt(DOWNTABLE.getValueAt(row+1, 5), row, 5);//已用时间.
			DOWNTABLE.setValueAt(DOWNTABLE.getValueAt(row+1, 6), row, 6);//文件类型.
			downLoad.row--;//每个线程对应行都要向上移动一个位置.
		}
		removeLock(rowFirst);//移除完成任务的锁.有效行减一.
		setLastRowNull();//最后一行清空.
	}
	
	
	/**
	 * 返回给定线程对象的的链接地址. 
	 * @param downLoad
	 * @return
	 */
	public String getURL(DownLoad downLoad)
	{
		return downLoad.link;
	}
	
	
	/**
	 * 返回给定线程对象的文件长度.
	 * @param downLoad
	 * @return
	 */
	public long getFileLength(DownLoad downLoad)
	{
		return downLoad.fileLength;
	}
	
	/**
	 * 返回给定线程对象的主机名. 
	 * @param downLoad
	 * @return
	 */
	public String getHost(DownLoad downLoad)
	{
		return downLoad.hostName;
	}
	
	
	/**
	 *清空最后一行.有任务完成,或删除任务时调用 
	 *
	 */
	private void setLastRowNull()
	{
		for(int i=0;i<7;i++)
		{
			SaveRunTime.getDOWN_TABLE().setValueAt("", SaveRunTime.getNEWTASK().getRow(), i);
		}
	}

	
	/**
	 * 移除给定行的下载线程锁,计时线程锁,保存在HashMap中对应的任务信息.表格有效行减一.
	 * @param row
	 */
	private synchronized  void removeLock(int row)
	{
		SaveRunTime.getLIST().remove(row);//线程锁,
		SaveRunTime.getTIMELIST().remove(row);//计时锁.
		SaveRunTime.getSAVE_HASHMAP().remove(row);//如果是一个无效的链接,hashMap中也将存放部着下载任务的部分信息
		SaveRunTime.getNEWTASK().setRow(SaveRunTime.getNEWTASK().getRow()-1);//有效行减一.
	}
}


/**
 * 线程类,测试给定链接是否有效.如果是,在启动下载线程后退出.
 *
 */
class TestLink implements Runnable
{
	private int count=0;//测试链接次数,
	private int row=0; //行索引
	private String url=null;//链接地址.
	private String choos=null;//保存路径.
	private String saveAs=null;//另存为文件名.
	private long point=0;//断点
	private static JTable tm=SaveRunTime.getDOWN_TABLE();//表格对象.
	private DownLoad downLoad=null;//下载线程.
	
	/**
	 * 构造方法,参数列表:1,行索引.2,链接地址,3,保存路径.4,保存文件名,5,断点.
	 * @param row
	 * @param url
	 * @param choos
	 * @param saveAs
	 * @param point
	 */
	public TestLink(int row,String url,String choos,String saveAs,long point)
	{
		this.row=row;
		this.url=url;
		this.choos=choos;
		this.saveAs=saveAs;
		this.point=point;
	}
	
	
	/**
	 * 测试链接地址.并决定是否去启动下载线程.
	 */
	public void run()
	{
		System.out.println("启动一个测试线程...");
		//创建一个下载线程.等待测试成功后启动.
		downLoad=new DownLoad(row,url,choos,saveAs,point);
		
		//不管链接是否有效,往集合类中添加锁.
		if(row==SaveRunTime.getLIST().size()) //如果是新行,将是最后一行.
		{	
			SaveRunTime.getLIST().add(downLoad);//下载线程.
		}
		if(row==SaveRunTime.getTIMELIST().size())//计时线程.永远不会是正在运行的计时线程对象.
		{														
			SaveRunTime.getTIMELIST().add(downLoad.new CounterThread());
		}
		
		
		//表格内容显示,
		linkError(0);

		boolean f=downLoad.fileInfo();//测试连接是否有效.

		if(f)//如果true,启动一个下载下线程.此方法被调用时,下载线程类部分属性将被赋值.
		{
			linkError(1);
			
			System.out.println("启动一个下载线程.....");
			new Thread(downLoad).start();
			
			try
			{
				Thread.sleep(1000);//睡眠一秒再写xml.
				new XmlOperation().writerTaskInfo();
			} catch (Exception ex)
			{
				ex.printStackTrace();
			}
			
			((DownLoad)SaveRunTime.getLIST().get(row)).setDownLoadSign(1);//设置下载线程运行状态.

			Thread.currentThread().interrupt();//中断测试线程.

			System.out.println("得到连接,测试线程中断:"+Thread.currentThread().isInterrupted());
		}
		else
		{
			HashMap<String,String> hm=new HashMap<String,String>(7);//有七个元素.
			hm.put("正在获取链接...","");
			hm.put("文件名称",saveAs);
			hm.put("文件长度","未知");
			hm.put("文件类型","未知");
			hm.put("保存路径",choos);	//不在测试十次后添加键值对.防止测试还没完成,右击删除键抛出异常.
			hm.put("链接地址",url);
			hm.put("对方主机","未知");
			SaveRunTime.getSAVE_HASHMAP().add(hm);

			while(count<11)
			{
				try
				{
					f=downLoad.fileInfo();
					if(f)
					{
						new Thread(downLoad).start();
						break;
					}
					//如果没得到链接.尝试连接5秒.
					System.out.println("尝试连接"+count+"次");
					Thread.sleep(500);
					if(count==10)
					{
						//传递连接失败信息.
						linkError(-1);
						try
						{
							//写入xml
							new XmlOperation().writerTaskInfo(); 
						} catch (Exception e)
						{
							e.printStackTrace();
						}
						System.out.println("连接失败,测试线程中断:"+Thread.currentThread().isInterrupted());
					}
					count++; 
				} catch (InterruptedException e) 
				{
					
				}
			}
			Thread.currentThread().interrupt();//中断线程.
		}
	}


	/**
	 * 控制表格信息变化.
	 * @param s
	 */
	private void linkError(int s)
	{
		tm.setValueAt(new XDownTable().getImageIcon("/image/ing.png"), row, 0);
		if(s==1)
		{	//返回连接成功信息.
			SaveRunTime.getDOWN_INFOTABLE().setValueAt("连接成功", 0, 1);
		}
		else if(s==-1)
		{
			//返回连接失败信息.
			tm.setValueAt(new XDownTable().getImageIcon("/image/die.png"), row, 0);
			SaveRunTime.getDOWN_INFOTABLE().setValueAt("连接失败", 0, 1);
		}
		
		//其它设置不变.
		tm.setValueAt(saveAs,row,1);
		tm.setValueAt(downLoad.new CounterThread().getProgress(point),row,2);
		tm.setValueAt("--",row,3);
		tm.setValueAt("--",row,4);
	}
}





/**
 * 
 * 	附: 
 * 			每个下载任务的开始会启动三个线程:首先由测试线程测试链接是否有效,接着启动下载线程,读到第一个字节后启动计时线程.
 * 			
 * 			计时线程总是由下载线程控制.
 * 
 * 			每个下载任务都有一个下载线程锁和计时线程锁.被分别保存在同步的List中,存放顺序与行索引相对应.
 * 
 * 			锁在测试线程中被添加,如果已经存在则不再添加.即控制线程运行状态的可能并不是正在运行的线程对象.
 * 			方便下载异常中断后,再次重新启动线程时继续控制.通过查看锁的downLoadSign值得知下载任务运行状态. 
 * 
 * 		 	关键变量: 行索引rowIndex,在newTaskDialog新建任务时进行累加.而不管下载线程是否会运行.
 * 
 * 			下载线程的开关变量,在碰到异常中断后,保留其-1值,不去改变.再次启动时判断.
 * 			对应的计时线程开关变量,在强制中断后设置成可运行状态.
 * 
 * 			一个下载任务完成后行索引值减一,需要在list中移除一个元素.其身后的所有对象的行索引都减一.
 * 				
 * 			所有通过SaveRunTime类得到的对象,都应该在使用前赋值.
 * 
 * 			读取到历史任务后的处理, 历史任务中任务condition值 为-3时任务图标设为暂停状态,与真正的线程暂停区分开来.
 * 			-1时为断开状态,不必区分.
 * 			
 * 			测试线程还没有退出时,避免右键删除带来的HashMap值为空时抛出的异常.(未完成)
 * 
 * 			程序加载历史任务时需要完成以下几个动作: 
 * 			1.给集合类中添加下载线程锁和计时线程锁.添加下载线程锁时需要调用DownLoad的带参构造方法,给部分属性赋值.
 * 			  计时线程锁,直接new.
 * 			2.DOWNINFOTABLE对应的hashMap添加键值对.
 * 			3.NewTask的属性rowIndex值等于历史任务的个数.
 * 
 * 		
 * 			
 * 			
 * 					
 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -