安卓之多线程下载

  多线程下载,最简单也是最直接的可以使用别人已经写好的框架,就不必重复造轮子了,可以参考github上的  xutils3 框架,支持文件上传下载等诸多功能,https://github.com/wyouflf/xUtils3

  下面记录一下自己使用randomaccessfile来实现下载功能的代码:

   1.在本地创建同将要下载的文件同大小的文件

int fileLength= con.getContentLength();
						//拿到操作文件的对象:
						RandomAccessFile ras= createRandomAccessFile(getFileName(path), fileLength);
//						ras.close();

  2.开启多个线程,并分配每个线程下载的文件大小

//启动三个线程去下载文件,同时要计算好每个线程下载的文件的起始位置
						int blockSize=fileLength/threadCount;
						for(int threadId=0;threadId<threadCount;threadId++){
							
							int startIndex=threadId*blockSize;
							int endIndex=(threadId+1)*blockSize-1;
							
							if(threadId==(threadCount-1)){
								endIndex=fileLength-1;
							}
							
							new DownloadFilePartThread(threadId,startIndex,endIndex)
								.start();
							
						}

3.循环的将读取到的数据写入到文件对应的位置中

int length=conn.getContentLength();
//获取服务器返回的数据,然后将返回的数据存入这个文件中
RandomAccessFile raf =createRandomAccessFile(getFileName(path), length);

InputStream in = conn.getInputStream();
//读取数据
int len=0;
byte[] buffer=new byte[1024];
while((len=in.read(buffer))>0){
  raf.write(buffer, 0, len);
}

为了避免在下载的时候服务器断掉致使下载内容要重新下载,可以边下载边记录以及下载到的位置并将其写入到某个文件中,然后下载的时候读取,并判断已经下载到的位置并设置起始下载的地方

<span style="font-size:14px;">currentPosition=currentPosition+len;
						
//						File info = new File(threadId + ".position");
//						RandomAccessFile rf = new RandomAccessFile(info, "rwd");
						
						RandomAccessFile rf =createRandomAccessFile(threadId + ".position",5);
						
						rf.write(String.valueOf(currentPosition).getBytes());
						rf.close();</span>

最后上整个下载的源码,虽然比较的简单但是也五脏俱全嘛

public class MainActivity extends ActionBarActivity {
	
	//规定服务器线程下载的数量
	private static int threadCount=3;
//	//记录正在进行下载的线程的数量
//	private static int runningThreadCount=3;
	//请求的服务器的地址:
	private static String path="http://192.168.110.102:8080/file.txt"; 

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//创建请求服务器的线程
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					URL url=new URL(path);
					HttpURLConnection con = (HttpURLConnection) url.openConnection();
					
					//设置请求的属性:
					con.setRequestMethod("GET");
					con.setReadTimeout(5000);
					
					int code=con.getResponseCode();
					
					//200:请求状态正常
					if(code==200){
						int fileLength= con.getContentLength();
						//拿到操作文件的对象:
						RandomAccessFile ras= createRandomAccessFile(getFileName(path), fileLength);
//						ras.close();
						
						//启动三个线程去下载文件,同时要计算好每个线程下载的文件的起始位置
						int blockSize=fileLength/threadCount;
						for(int threadId=0;threadId<threadCount;threadId++){
							
							int startIndex=threadId*blockSize;
							int endIndex=(threadId+1)*blockSize-1;
							
							if(threadId==(threadCount-1)){
								endIndex=fileLength-1;
							}
							
							new DownloadFilePartThread(threadId,startIndex,endIndex)
								.start();
							
						}
					}
				} catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	/**
	 * 如果手机有root了,可以直接这样写
	 * 		File file = new File(getFileName(path));
			RandomAccessFile raf = new RandomAccessFile(file, "rw");
			raf.setLength(length);
			raf.close();
	 * @param fileName  
	 * @param length
	 * @return
	 */
	public RandomAccessFile createRandomAccessFile(String fileName,int length){
		String filePath = this.getFilesDir().getPath().toString() + "/"+fileName;
		System.out.println(filePath);
		File file=new File(filePath);
		RandomAccessFile ras=null;
		try {
			ras = new RandomAccessFile(file, "rw");
			ras.setLength(length);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ras;
	}
	
	/**
	 * 根据路径返回文件的名称:
	 * @param path
	 * @return
	 */
	public static String getFileName(String path){
		int index=path.lastIndexOf("/");
		return path.substring(index+1);
	}
	
	class DownloadFilePartThread extends Thread{
		
		//线程的ID号
		private int threadId;
		
		//线程的起始位置
		private int startIndex;
		
		//线程的结束位置
		private int endIndex;
		
		//线程当前下载到的位置
		private int currentPosition;
		
		public DownloadFilePartThread(int threadId, int startIndex, int endIndex) {
			super();
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			
			currentPosition = startIndex;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			System.out.println("第 " + threadId + "线程开始 下载了   : 下载  从 "
					+ startIndex + "~ " + endIndex);
			
			try {
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				
				conn.setConnectTimeout(5000);
				conn.setRequestMethod("GET");
				
				// 在多线 程 下载的时候 , 每条线程 只需要 目标 文件的 一部分的数据
				// 需要 告诉 服务器, 只需要 那一段的数据
				// 通过 设置 http的 请求头 可以去实现 , 告诉 服务器, 只需要目标 段的数据

				//告诉服务器下载的起始位置: startIndex ---- endIndex 
//				conn.setRequestProperty("range", "bytes=" + startIndex + "-"
//						+ endIndex);
				
				//创建写currentPosition的文件来判断文件是否被下载过
				int alreadyWritePosition=0;
				File f=new File(threadId+".postion");
				if(f.exists()&&f.length()>0){
					//表示曾经下载过,则读取这个已经下载到的位置,然后继续下载
					alreadyWritePosition= getPositionInFile(f);
					
					// 告诉 服务器要数据的时候 ,从这个位置 开始 要
					conn.setRequestProperty("range", "bytes="
							+ alreadyWritePosition + "-" + endIndex);
					
					//要告诉服务器从哪个位置开始写
//					raf.seek(alreadyWritePosition);
				}else{
					conn.setRequestProperty("range", "bytes=" + startIndex
							+ "-" + endIndex);
					// 要 告诉 从哪个位置开始写
//					raf.seek(startIndex);
				}
				
				int length=conn.getContentLength();
				//获取服务器返回的数据,然后将返回的数据存入这个文件中
				RandomAccessFile raf =createRandomAccessFile(getFileName(path), length);
				
				if(alreadyWritePosition!=0){
					raf.seek(alreadyWritePosition);
				}else{
					raf.seek(startIndex);
				}
				
				
				//返回部分数据,如果成功状态码是206
				int code = conn.getResponseCode();
				//将获得的数据写入文件中:
				if(code==206){
					InputStream in = conn.getInputStream();
					
					//读取数据
					int len=0;
					byte[] buffer=new byte[1024];
					while((len=in.read(buffer))>0){
						raf.write(buffer, 0, len);
						String context=threadId+","+ new String(buffer)+","+startIndex+","+endIndex;
						//记录实时位置并写入 threadId.postion文件中
						currentPosition=currentPosition+len;
						
//						File info = new File(threadId + ".position");
//						RandomAccessFile rf = new RandomAccessFile(info, "rwd");
						
						RandomAccessFile rf =createRandomAccessFile(threadId + ".position",5);
						
						rf.write(String.valueOf(currentPosition).getBytes());
						rf.close();
					}
				}
				
//				System.out.println("第 " + threadId + "线程 下载  结束   了 ");
				Log.i("out", "第 " + threadId + "线程 下载  结束   了 ");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		
		public  int getPositionInFile(File file){
			int readPosition=0;
			try {
				BufferedReader bfr=new BufferedReader(new FileReader(file));
				String context=bfr.readLine();
				readPosition=Integer.valueOf(context);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return readPosition;
		}
	}
	
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值