多线程下载,断点续传原理解析和代码实现
来源:互联网 发布:2017淘宝客服工作计划 编辑:程序博客网 时间:2024/06/06 00:52
- 多线程下载
- 实现步骤
- 注意的问题
- 代码实现
- 进度条用单独一个LinearLayout
- 获取文件总大小
- 为将要下载的文件预留空间
- 计算每个子线程要下载的字节范围
- 下载子线程是部分请求设置请求头
- 设置子线程写入位置并写入文件
- 判断下载完成
- 关于RandomAccessFile类
- 该案例中用到了以下方法
- 代码实现
- 断点续传
- 原理
- 每写入一次就保存一次当前写入的位置
- 子下载线程开启时检测是否有断点续传
- 进度条的设置
- 原理
- 开源项目实现多线程下载
- 源码下载
多线程下载
实现步骤:
- 先获取到服务器上的资源大小
- 在客户端创建一个大小和服务器一样的文件
- 假设开3个线程,算出每个线程下载的的开始位置和结束位置
- 开启线程去下载
注意的问题
- 测试时为了保证效果,使用.exe安装程序 做测试
只要丢了一个字节该程序便不能使用 - 先使用javase工程写,再移植到Android工程
- RandomAccessFile类。创建从其中随机读取或者写入的访问流
- 元数据:数据的数据(数据的属性),比如一个文件的名称,大小,路径等都是这个文件的元数据
代码实现
布局:
进度条用单独一个LinearLayout
再设置它的布局内容为ProgressBar
获取文件总大小
//連接服務器URL url = new URL(urlStr);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5 * 1000);//獲取返回狀態碼int code = conn.getResponseCode();if(code == 200) { //請求成功,獲取服務器返回文件的大小 int length = conn.getContentLength(); Log.d("文件大小為:", length + "");}
为将要下载的文件预留空间
//請求成功,獲取服務器返回文件的大小int length = conn.getContentLength();LogUtil.d("文件大小為:", length + "");RandomAccessFile raf = new RandomAccessFile(sdPath + "/" + getFileName(urlStr), "rw");//為將要下載的文件預先分配空間raf.setLength(length);
计算每个子线程要下载的字节范围
//開啟多個線程,分段下載for(int i=0; i<threadCount; i++) { //計算每個線程應該下載的字節範圍 int startIndex = i * blockSize; int endIndex = (i + 1) * blockSize - 1; //如果是最後一個線程,就下載到文件末尾 if(i == threadCount - 1) { endIndex = length - 1; } new DownLoadThread(startIndex, endIndex, i).start();}
下载子线程是部分请求,设置请求头
HttpURLConnection conn = connct2Server(urlStr);//設置Range頭屬性conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
设置子线程写入位置并写入文件
if(code == 206) { //部份資源請求成功 LogUtil.d("線程" + threadId + "請求成功", code + ""); //拿到要寫入的文件 RandomAccessFile raf = new RandomAccessFile(sdPath + "/" + getFileName(urlStr), "rw"); //設置要寫入的文件光標位置 raf.seek(startIndex); //獲取輸入流并寫入文件 InputStream is = conn.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); byte[] buffer = new byte[1024 * 1024]; int len = 0; while((len = bis.read(buffer)) != -1) { raf.write(buffer, 0, len); } raf.close(); bis.close();}
判断下载完成
//下載完畢后提示synchronized (DownLoadThread.class) { threadCount --; if(threadCount == 0) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "下載完畢", 1).show(); } }); }}
关于RandomAccessFile类
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。
该案例中用到了以下方法
构造方法:RandomAccessFile raf = new RandomAccessFile(sdPath + "/" + getFileName(urlStr), "rw");
写入方法:raf.write(buffer, 0, len);
设置文件指针位置:raf.seek(startIndex);
断点续传
原理
当线程被结束时,把当前下载到的文件字节下标保存到文件中。
当下载线程再次开启时,从文件中读取下载到的位置,从这里开始下载。
每写入一次就保存一次当前写入的位置
fos.close();//使用原来的方法可能导致没有来得及保存RandomAccessFile pos = new RandomAccessFile(sdDir + "/" + getFileName(path) + "Thread-" + threadId + ".txt", "rwd");pos.write(String.valueOf(currentTreadPostion).getBytes());pos.close();
子下载线程开启时,检测是否有断点续传
把从文件读取出来 的位置赋值给startIndex
//打开保存断点位置的文件File file = new File(sdDir + "/" + getFileName(path) + "Thread-" + threadId + ".txt");if(file.exists() && file.length() > 0) { //说明中断过,把上次断点位置读取出来 FileInputStream fis = new FileInputStream(file); BufferedReader br= new BufferedReader(new InputStreamReader(fis)); String lastPos = br.readLine(); //获取上次下载的进度条位置 pbLastPosition = Integer.parseInt(lastPos) - startIndex; //改变下一次的开始位置 startIndex = Integer.parseInt(lastPos); br.close();}
进度条的设置
每下载一次就设置一次进度条的位置
//进度条的初始化ll_progress.removeAllViews();//加载进度条之前先清除之前的进度条//动态加载进度条for(int i=0; i<threadCount; i++) {//使用打气筒服务用布局文件创建一个进度条对象 ProgressBar pb = (ProgressBar) View.inflate(getApplicationContext(), R.layout.pb, null); pb.setMax(100);//设置进度条的最大值 pb.setProgress(50);//设置进度条的当前进度 pbs.add(pb);//进度条对象添加 到集合 ll_progress.addView(pb);//添加一个进度条到总布局 }//进度条的更新,子线程可以更新进度条pbs.get(threadId).setMax(pbMax);pbs.get(threadId).setProgress(pbLastPosition + total);
开源项目实现多线程下载
了解了多线程断点下载的原理,在实际应用中更多的是使用开源项目,可以大大降低成本,节省时间。
使用方法如下 :
导入xUtils包,使用就行
path = tv_url.getText().toString().trim();//创建HttpUtils对象HttpUtils httpUtils = new HttpUtils();//autoResume支持断点续传httpUtils.download(path, "mnt/sdcard/haha.exe", true, new RequestCallBack<File>() {@Overridepublic void onSuccess(ResponseInfo<File> responseInfo) { Toast.makeText(getApplicationContext(), "下载成功", 1).show();}//更新进度条的方法@Overridepublic void onLoading(long total, long current, boolean isUploading) { pb.setMax((int)total); pb.setProgress((int)current); super.onLoading(total, current, isUploading);}@Overridepublic void onFailure(HttpException error, String msg) {}
源码下载
http://download.csdn.net/detail/jianbiao426/9553462
0 0
- 多线程下载,断点续传原理解析和代码实现
- Java代码实现多线程下载和断点续传
- Java代码实现多线程下载和断点续传
- Android 中实现多线程下载和断点续传的原理和代码
- http协议学习-断点续传和多线程下载的实现原理
- Android实现网络多线程断点续传下载原理
- Java实现多线程下载和断点续传
- android实现断点续传和多线程下载
- android 实现多线程下载和断点续传
- 断点续传下载原理实现
- 断点续传下载原理实现
- 断点续传下载原理实现
- 断点续传下载原理实现
- 断点续传下载原理实现
- 多线程下载和断点续传
- 多线程下载和断点续传
- 断点续传和多线程下载
- 多线程断点续传文件下载原理
- FPGA基础之锁存器与触发器的设计
- STL-power算法实现
- SMO算法总结
- cheet 6 深搜和广搜
- 【VS开发】【Linux开发】【DSP开发】如何截获以太网帧并解析
- 多线程下载,断点续传原理解析和代码实现
- 结构体进程描述进程
- 为什么UI线程是不安全线程
- 用IO流的知识将两个文件写到一个文件中(设置字符编码)
- SwipeRefreshLayout 源码
- acm_最短路
- 质数因子
- 处理下载文件时中文乱码
- 对于解析xls(excle表格数据 )