java多线程断点续传

 在android下面的断点续传和java下面没有太大的冲突,就是在配置文件里面加上一些特定的访问权限就可以了
如下式在AndroidManifest.xml加入的权限
 
<!--  访问internet权限 -->
       <uses-permission android:name="android.permission.INTERNET" />
       <!--  在SDCard中创建与删除文件权限-->
       <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
       <!--  往SDCard写入数据权限-->
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
这个准备工作做好了就可以直接编码了
第一步创建multiThreaddownload.java
 
package com.cn.download;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
 
import com.cn.coocaa.download.FileDownloadThread;
 
public class MultiThreadDownload extends Thread {
        //定义的一些常量变量,看名字就知道什么意思了
	private static final int BUFFER_SIZE = 1024;
	private int blockSize;
	private int threadNum = 5;
	private int fileSize;
	private int downloadedSize;
	String urlStr, threadNo, fileName;
	private String savePath;
	private int downloadPercent = 0 , downloadSpeed = 0, usedTime=0;
	private long startTime,curTime;
	private	boolean completed = false;
        //用URL,保存路径,保存名称来构造。
	public MultiThreadDownload(String URL, String savePath, String fileName) {
		this.urlStr = URL;
		this.savePath = savePath;
		this.fileName = fileName;
	}
 
	@Override
	public void run() {
		FileDownloadThread[] fds = new FileDownloadThread[threadNum];
		try {
			URL url = new URL(urlStr);
			URLConnection conn = url.openConnection();
			fileSize = conn.getContentLength();
			blockSize = fileSize / threadNum;
			File file[] = new File[threadNum];
                        //根据默认的线程数,或者自己修改设置的线程数来分块,创建分块后的文件块
			for (int i = 0; i < threadNum; i++) {
				file[i] = new File(savePath + fileName + ".part"
						+ String.valueOf(i));
                                //将分块的文件交给每个线程处理,最后一块应该大于等于平均块,因为可能有余数
				FileDownloadThread fdt = new FileDownloadThread(url, file[i], i
						* blockSize, (i + 1) != threadNum ? ((i + 1)
						* blockSize - 1) : fileSize);
				fdt.setName("Thread" + i);
				fdt.start();
				fds[i] = fdt;
			}
			startTime = System.currentTimeMillis();
                        //获取起始下载的时间,用次来计算速度。
			boolean finished = false;
			while (!finished) {
				downloadedSize = 0;
				finished = true;
				for (int i = 0; i < fds.length; i++) {
					downloadedSize += fds[i].getDownloadSize();
					if (!fds[i].isFinished()) {
						finished = false;
					}
				}
                                //计算下载的百分比
				downloadPercent = (downloadedSize*100)/fileSize;
                                //获取当前时间,计算平均下载速度
				curTime = System.currentTimeMillis();
				usedTime =(int)((curTime-startTime)/1000);
				if(usedTime==0)
					usedTime =1;
				downloadSpeed = (downloadedSize/usedTime)/1024;
				sleep(1000);
			}
                       //这个是分块下载完成的标志
			completed = true;
                        //进行模块整合
			RandomAccessFile raf = new RandomAccessFile(savePath + fileName,
					"rw");
			byte[] tempbytes = new byte[BUFFER_SIZE];
			InputStream in = null;
			int byteread = 0;
			for (int i = 0; i < threadNum; i++) {
				in = new FileInputStream(file[i]);
				while ((byteread = in.read(tempbytes)) != -1)
				{
					raf.write(tempbytes, 0, byteread);
				}
                                //每次整合完一块就删除一块。
				in.close();
				file[i].delete();
			}
			raf.close();
 
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
       //获取下载百分比
	public int getDownloadPercent(){
		return this.downloadPercent;
	}
       //获取下载速度
	public int getDownloadSpeed(){
		return this.downloadSpeed;
	}
       //修改默认线程数
	public void setThreadNum(int threadNum){
		this.threadNum = threadNum;
	}
        //分块下载完成的标志
	public boolean isCompleted(){
		return this.completed;
	}
}
第二步 创建filedownloadthread.java
package com.cn.download;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
 
public class FileDownloadThread extends Thread {
	private static final int BUFFER_SIZE = 1024;
	private URL url;
	private File file;
	private int startPosition;
	private int endPosition;
	private int curPosition;
	private boolean finished = false;
	private int downloadSize = 0;
       //分块构造函数
	public FileDownloadThread(URL url, File file, int startPosition,
			int endPosition) {
		this.url = url;
		this.file = file;
		this.startPosition = startPosition;
		this.curPosition = startPosition;
		this.endPosition = endPosition;
	}
 
	public void run() {
 
 
		BufferedInputStream bis = null;
		RandomAccessFile fos = null;
		byte[] buf = new byte[BUFFER_SIZE];
		URLConnection con = null;
		try {
                       //打开URL连接
			con = url.openConnection();
			con.setAllowUserInteraction(true);
                       //判断是否该文件存在,如果存在且下载完成,直接返回。
			if ((file.length() + startPosition) == endPosition) {
				this.finished = true;
			}
                        //文件未下载完成,获取到当前指针位置,继续下载。
                         else {
				con.setRequestProperty("Range", "bytes="
						+ (startPosition + file.length()) + "-" + endPosition);
				fos = new RandomAccessFile(file, "rw");
				fos.seek(file.length());
				bis = new BufferedInputStream(con.getInputStream());
				while (curPosition < endPosition) {
					int len = bis.read(buf, 0, BUFFER_SIZE);
					if (len == -1) {
						break;
					}
					fos.write(buf, 0, len);
					curPosition = curPosition + len;
					if (curPosition > endPosition) {
						downloadSize += len - (curPosition - endPosition) + 1;
					} else {
						downloadSize += len;
					}
				}
				this.finished = true;
				bis.close();
				fos.close();
			}
		} catch (IOException e) {
			System.out.println(getName() + " Error:" + e.getMessage());
		}
	}
 
	public boolean isFinished() {
		return finished;
	}
 
	public int getDownloadSize() {
		return downloadSize;
	}
}
上述两个文件就完成了多线程断点续传。
 
 
 
无需使用任何配置文件或者数据库,就可以接上次的断点进行续传操作。
 
原理流程:
         1、获取文件大小
         2、将文件按照所设定的线程数进行分块请求。
         3、检查是否存在断点情况,如果有断点情况则进行断点查找,然后再请求。
         4、分块下载。
         5、下载完成后文件整合,将分块文件删除掉。
         6、好了,你需要下载的文件就可以完成了。
 
 
总之了,在这里也是一种实现无需配置文件的方式吧,我提供的只是一个外部调用包,所以这个配置文件或者数据库记录的东西有很大的局限性,所以就切割了,
 
如果有什么更好的想法,希望能相互交流交流。
 
转载请注明:http://alloxa.blog.51cto.com/
 
 
 

你可能感兴趣的:(java多线程断点续传)