Android下使用Http协议实现多线程断点续传下载
在Android应用中使用OkHttp实现网络请求
在Android应用中使用OkHttp实现网络请求Android应用的网络请求通常需要用到网络框架,为了更快、更可靠地进行网络请求,近年来,OkHttp已成为Android开发者们常用的网络框架之一。
接下来,我们将就如何在Android应用中使用OkHttp实现网络请求进行详细介绍。
一、OkHttp介绍OkHttp是一个安卓平台下的HTTP框架,该框架通过小巧的封装,提供了高效的方式进行网络请求。
OkHttp的主要特点如下:1. 具有多种请求方式,支持GET、POST等常见的网络请求方式。
2. 支持同步、异步网络请求,满足不同业务需求场景。
3. 支持请求链式调用、相应数据链式传递,易于使用和管理。
4. 支持动态代理技术,通过动态代理将网络请求的响应数据映射到Java对象中。
二、OkHttp的使用在开始使用OkHttp之前,我们需要在项目中添加相应的依赖库,可以通过Gradle来添加:```compile 'com.squareup.okhttp3:okhttp:3.7.0'```接下来,我们可以通过以下步骤来使用OkHttp:1. 首先创建OkHttpClient对象。
```OkHttpClient okHttpClient = new OkHttpClient();```2. 封装请求对象,选择请求方式(get或post)并填充请求参数。
```Request request = new Request.Builder().url(url).get() //选择get请求方式.build(); //封装请求参数```3. 通过创建Call对象执行网络请求,并获得响应结果。
```Call call = okHttpClient.newCall(request);Response response = call.execute();```以上三步完成了一个简单的网络请求,接下来我们可以从这个简单的网络请求入手,更深入地了解OkHttp的使用。
http协议下载文件
http协议下载⽂件1. 通过在 URL 上调⽤ openConnection ⽅法创建连接对象。
(HttpURLConnection conn = (HttpURLConnection)new URL("⽹址").openConnection();)2. 处理设置参数和⼀般请求属性。
(conn.setRequestProperty())3. 使⽤ connect ⽅法建⽴到远程对象的实际连接。
(conn.connect())4. 远程对象变为可⽤。
远程对象的头字段和内容变为可访问。
(conn.getHeaderField(),conn.getInputStream等⽅法对连接进⾏操作)下⾯是对⽂件下载的具体实现案例(单线程):HttpURLConnection conn = (HttpURLConnection)new URL("资源⽹址").openConnection();conn.connect();InputStream is = connection.getInputStream();FileOutputStream os = new FileOutputStream("保存路径");int count = 1024;if(connection.getResponseCode()==200){while ((count = is.read(b))!=-1) {os.write(b,0,count);}os.close();is.close();}多线程要设置的头⽂件:connection.setRequestProperty("Range", "bytes=0-4194304");/*有个疑惑:代码这样写的话,出现⽂件下载不全。
while (count==1024) {count = is.read(b)os.write(b,0,count);}*/。
C#实现支持断点续传多线程下载的 Http Web 客户端工具类
Throw,
CancelAll,
Ignore,
Retry
}
/// <summary>
/// 包含 Exception 事件数据的类
/// </summary>
public class ExceptionEventArgs : System.EventArgs
{
private System.Exception _Exception;
private ExceptionActions _ExceptionAction;
private DownLoadState _DownloadState;
public DownLoadState DownloadState
namespace Microshaoft.Utils
{
using System;
using System.IO;
using ;
using System.Text;
using System.Security;
using System.Threading;
{
get
{
return _ExceptionAction;
}
set
{
_ExceptionAction = value;
}
}
internal ExceptionEventArgs(System.Exception e, DownLoadState DownloadState)
this._Position = Position;
this._Data = Data;
this._Length = Length;
android 断点续传原理
android 断点续传原理
断点续传是一种在下载或上传过程中,如果因为某种原因导致传输中断,能够从中断点继续传输文件的技术。
在Android中实现断点续传主要涉及到
以下几个关键点:
1. 文件分块:首先,需要将文件分割成多个小块。
每个小块都可以单独传输,并在传输完成后进行校验。
2. 记录已传输块的位置:在传输过程中,需要记录每个块已传输的位置。
如果传输中断,可以从最后一个已完成的位置继续传输。
3. 支持多种传输协议:Android可能需要支持多种不同的传输协议,如HTTP、FTP、BT、磁力链接等,每种协议的断点续传实现方式可能有所不同。
4. 错误处理和恢复机制:在传输过程中,可能会遇到各种错误,如网络断开、服务器宕机等。
需要设计相应的错误处理和恢复机制,确保文件能够完整传输。
5. 使用现有的库或框架:为了简化开发工作,可以使用现有的库或框架来实现断点续传功能。
例如,Android的Volley库就支持断点续传功能。
6. 测试和优化:在实际应用中,可能需要对断点续传功能进行大量的测试和优化,以确保其稳定性和性能。
在实现断点续传功能时,需要考虑的方面有很多,但基本原理就是对文件进行分块处理,并记录每个块已传输的位置,以便在传输中断时能够从中断点继续传输。
断点续传方案
断点续传方案简介断点续传是指在网络传输过程中,当连接中断或者文件传输中止时,能够从中断处重新开始传输,而不是从头开始。
这样可以提高文件传输的可靠性和传输效率。
在实际应用中,断点续传方案常常用于大文件的上传或下载过程中,以确保用户在网络不稳定的情况下能够顺利完成文件传输,而无需重新开始。
本文将介绍几种常见的断点续传方案,并分析各种方案的优缺点,帮助读者选择适合自己应用场景的方案。
方案一:基于HTTP的断点续传HTTP协议是应用层协议中最常用的协议之一,支持断点续传的HTTP服务器通常会在响应头中添加Range字段,用于指定服务器传输的起始位置。
客户端在进行文件下载时,通过设置请求头中的Range字段来请求指定范围的数据。
服务器接收到请求后,根据Range字段返回相应的数据片段。
如果客户端在下载过程中中断,可以通过设置Range字段重新发送请求,从中断处继续下载。
HTTP的断点续传方案具有以下优点:-:基于HTTP的断点续传方案使用标准的HTTP协议,不需要额外的协议和框架支持,方便快捷。
-:基于HTTP的断点续传方案通常兼容多种操作系统和终端设备,使用广泛。
-:通过设置不同的Range字段,可以实现下载指定范围的数据,具有较高的灵活性。
-:HTTP协议本身就具有较高的可靠性,断点续传方案在一定程度上增强了文件传输的可靠性。
然而,基于HTTP的断点续传方案也存在一些局限性:-:由于每次续传都需要从中断处开始,可能会导致重复传输已经传输过的数据,降低传输效率。
-:对于非常大的文件,服务器需要保存大量的中断点信息,占用较多的磁盘空间和内存资源。
-:如果服务器不支持断点续传,那么即使客户端实现了断点续传方案,也无法成功续传。
方案二:基于FTP的断点续传FTP(File Transfer Protocol)是一种文件传输协议,也常用于文件上传和下载。
FTP支持断点续传的机制,能够在网络中断或传输中止后从中断处继续传输。
Android基于OkHttp实现下载和上传图片
Android基于OkHttp实现下载和上传图⽚本⽂实例为⼤家分享了OkHttp实现下载图⽚和上传图⽚的具体代码,供⼤家参考,具体内容如下MainActivity.javapublic class MainActivity extends AppCompatActivity {private String Path = "https:///eth/ajNVdqHZLLAxibwnrOxXSzIxA76ichutwMCcOpA45xjiapneMZsib7eY4wUxF6XDmL2FmZEVYsf86iaw/"; private static final int SUCCESS = 993;private static final int FALL = 814;Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {//加载⽹络成功,进⾏UI的更新,处理得到的图⽚资源case SUCCESS://通过message,拿到字节数组byte[] Picture = (byte[]) msg.obj;//使⽤BitmapFactory⼯⼚,把字节数组转换为bitmapBitmap bitmap = BitmapFactory.decodeByteArray(Picture, 0, Picture.length);//通过ImageView,设置图⽚mImageView_okhttp.setImageBitmap(bitmap);break;//当加载⽹络失败,执⾏的逻辑代码case FALL:Toast.makeText(MainActivity.this, "⽹络异常", Toast.LENGTH_SHORT).show();break;default:break;}}};private ImageView mImageView_okhttp;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);//初始化控件initView();}private void initView() {mImageView_okhttp = (ImageView) findViewById(R.id.imageView_okhttp);}/*** 根据点击事件获取络上的图⽚资源,使⽤的是OKhttp框架** @param view*/public void Picture_okhttp_bt(View view) {//1. 创建OKhttpClient对象OkHttpClient okHttpClient = new OkHttpClient();//2.建⽴Request对象,设置参数,请求⽅式如果是get,就不⽤设置,默认使⽤的就是getRequest request = new Request.Builder().url(Path)//设置请求⽹址.build();//建⽴request对象//3.创建⼀个Call对象,参数是request对象,发送请求Call call = okHttpClient.newCall(request);//4.异步请求,请求加⼊调度call.enqueue(new Callback() {@Override//请求失败回调public void onFailure(Call call, IOException e) {handler.sendEmptyMessage(FALL);}@Override//请求成功回调public void onResponse(Call call, Response response) throws IOException {//得到从⽹上获取资源,转换成我们想要的类型byte[] Picture_bt = response.body().bytes();//通过handler更新UIMessage message = handler.obtainMessage();message.obj = Picture_bt;message.what = SUCCESS;handler.sendMessage(message);}});}//当按钮点击时,执⾏使⽤OKhttp上传图⽚到服务器(/tangxl2008008/article/details/51777355)//注意:有时候上传图⽚失败,是服务器规定还要上传⼀个Key,如果开发中关于⽹络这⼀块出现问题,就多和⾯试官沟通沟通 public void uploading(View view) {//图⽚上传接⼝地址String url = "https:///sell/sell.m.picture.upload.do";//创建上传⽂件对象File file = new File(Environment.getExternalStorageDirectory(), "big.jpg");//创建RequestBody封装参数RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);//创建MultipartBody,给RequestBody进⾏设置MultipartBody multipartBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("image", "big.jpg", fileBody).build();//创建RequestRequest request = new Request.Builder().url(url).post(multipartBody).build();//创建okhttp对象OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).build();//上传完图⽚,得到服务器反馈数据okHttpClient.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.e("ff", "uploadMultiFile() e=" + e);}@Overridepublic void onResponse(Call call, Response response) throws IOException {Log.i("ff", "uploadMultiFile() response=" + response.body().string());}});}}activity_main.xml<RelativeLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.sn.picture_okhttp.MainActivity"><Buttonandroid:id="@+id/button"android:onClick="Picture_okhttp_bt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下载图⽚"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:layout_marginTop="59dp"/><Buttonandroid:text="上传图⽚"android:onClick="uploading"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/button2"android:layout_alignParentTop="true"android:layout_alignLeft="@+id/button"android:layout_alignStart="@+id/button"/><ImageViewandroid:id="@+id/imageView_okhttp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"/></RelativeLayout>build.gradle //依赖implementation 'com.squareup.okhttp3:okhttp:3.4.2'以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
用Java实现HTTP断点续传——多线程下载文件
用Java实现HTTP断点续传——多线程下载文件钟华本文介绍了一种利用Java 来实现断点续传的方法。
断点续传的原理Http断点续传的原理其实很简单,就是在请求上和一般的下载有所不同而已。
例如浏览器请求服务器上的一个文件时,所发出的请求如下(假设服务器域名为,文件名为down.zip):GET /down.zip HTTP/1.1Accept: image/gif, image/x-xbitmap, image/jpeg, image/jpg,application/vnd.ms-excel, application/msword,application/vnd.ms-powerpoint, */*Accept-Language: zh-cnAccept-Encoding: gzip, deflautUser-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) Connection: Keep-Alive服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:200Content-Length=106786028Accept-Ranges=bytesDate=Mon, 30 Apr 2001 12:56:11 GMTETag=W/"02ca57e173c11:95b"Content-Type=application/octet-streamServer=Microsoft-IIS/5.0Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT所谓断点续传,就是从文件已经下载的地方开始继续下载。
所以在客户端浏览器传给Web服务器的时候要多加一条信息——从哪里开始。
下面是用自己编的一个“浏览器”来传递请求信息给Web服务器,要求从2000070字节开始。
android多线程下载技术详解
Android 多线程、断点续传下载技术1.为什么使用该技术?答:(1)之所以采用多线程下载是因为考虑到手机,及移动设备的cup处理能力,让下载任务多抢占cup资源,从而加快了下载的速度,提高了用户体验(2)断点续传技术,就是在下载过程中如果网络出现问题,导致文件没有下载完,那么下次下载时,接着上次终端位置继续下载,从而减轻了服务器的负担。
2.下面我们就开始建一个多线程下载的项目,来体验多线程下载的优势,项目的结构如下2.1设计UImain.xml代码如下:<?xml version="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res /android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/path"/><EditTextandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="/kcn/pc/K anbox_10012.exe"android:id="@+id/path"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button"android:id="@+id/button"/><ProgressBarandroid:layout_width="fill_parent"android:layout_height="20px"style="?android:attr/progressBarStyleHorizontal"android:id="@+id/downloadbar"/><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center"android:id="@+id/result"/></LinearLayout>其中引用的string.xml如下:<?xml version="1.0"encoding="utf-8"?><resources><string name="hello">Hello World, SmartDownload!</string><string name="app_name">SMART多线程断点下载器</string><string name="path">下载路径</string><string name="button">下载</string><string name="success">下载完成</string><string name="error">下载失败</string><string name="sdcarderror">SDCard不存在或者写保护</string></resources>3.数据库阶段:3.1编写数据库工具类DBOpenHelerpackage com.smart.db;import android.content.Context;import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper;public class DBOpenHelper extends SQLiteOpenHelper {private static final String DBNAME = "smart.db";private static final int VERSION = 1;public DBOpenHelper(Context context) {super(context, DBNAME, null, VERSION);}@Overridepublic voiddb.execSQL("CREATE TABLE IF NOT EXISTS SmartFileDownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER)");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS SmartFileDownlog");onCreate(db);}}3.2对各个线程的下载记录进行数据库的操作,编写Fileservice 类代码如下package com.smart.db;import java.util.HashMap;import java.util.Map;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase; /*** 业务bean**/public class FileService {private DBOpenHelper openHelper;public FileService(Context context) { openHelper = new DBOpenHelper(context);}/*** 获取每条线程已经下载的文件长度* @param path* @return*/public Map<Integer, Integer> getData(String path){openHelper.getReadableDatabase();Cursor cursor = db.rawQuery("select threadid, downlength from SmartFileDownlog where downpath=?", new String[]{path});Map<Integer, Integer> data = newHashMap<Integer, Integer>();while(cursor.moveToNext()){data.put(cursor.getInt(0),cursor.getInt(1));}cursor.close();db.close();return data;}/*** 保存每条线程已经下载的文件长度* @param path* @param map*/public void save(String path, Map<Integer, Integer> map){//int threadid, int positionopenHelper.getWritableDatabase();db.beginTransaction();try{for(Map.Entry<Integer, Integer> entry : map.entrySet()){db.execSQL("insert intoSmartFileDownlog(downpath, threadid, downlength) values(?,?,?)",new Object[]{path, entry.getKey(), entry.getValue()});}db.setTransactionSuccessful();}finally{db.endTransaction();}db.close();}/*** 实时更新每条线程已经下载的文件长度* @param path* @param map*/public void update(String path, Map<Integer, Integer> map){SQLiteDatabase db =openHelper.getWritableDatabase();db.beginTransaction();try{for(Map.Entry<Integer, Integer> entry : map.entrySet()){db.execSQL("update SmartFileDownlog set downlength=? where downpath=? and threadid=?",new Object[]{entry.getValue(), path, entry.getKey()});}db.setTransactionSuccessful();}finally{db.endTransaction();}db.close();}/*** 当文件下载完成后,删除对应的下载记录* @param path*/public void delete(String path){SQLiteDatabase db =openHelper.getWritableDatabase();db.execSQL("delete from SmartFileDownlog where downpath=?", new Object[]{path});db.close();}}4.实现文件下载阶段4.1建立SmartFileDownloader类用来实现文件的下载功能代码如下package com.smart.impl;import java.io.File;import java.io.RandomAccessFile;import .HttpURLConnection;import .URL;import java.util.LinkedHashMap;import java.util.Map;import java.util.UUID;import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher;import java.util.regex.Pattern;import android.content.Context;import android.util.Log;import com.smart.db.FileService;public class SmartFileDownloader {private static final String TAG = "SmartFileDownloader";private Context context;private FileService fileService;/* 已下载文件长度 */private int downloadSize = 0;/* 原始文件长度 */private int fileSize = 0;/* 线程数 */private SmartDownloadThread[] threads;/* 本地保存文件 */private File saveFile;/* 缓存各线程下载的长度*/private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>();/* 每条线程下载的长度 */private int block;/* 下载路径 */private String downloadUrl;/*** 获取线程数*/public int getThreadSize() {return threads.length;}/*** 获取文件大小* @return*/public int getFileSize() {return fileSize;}* 累计已下载大小* @param size*/protected synchronized void append(int size) { downloadSize += size;}/*** 更新指定线程最后下载的位置* @param threadId 线程id* @param pos 最后下载的位置*/protected void update(int threadId, int pos) { this.data.put(threadId, pos);}/*** 保存记录文件*/protected synchronized void saveLogFile() { this.fileService.update(this.downloadUrl, this.data);}* 构建文件下载器* @param downloadUrl 下载路径* @param fileSaveDir 文件保存目录* @param threadNum 下载线程数*/public SmartFileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum) {try {this.context = context;this.downloadUrl = downloadUrl;fileService = newFileService(this.context);URL url = new URL(this.downloadUrl);if(!fileSaveDir.exists())fileSaveDir.mkdirs();this.threads = newSmartDownloadThread[threadNum];HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5*1000);conn.setRequestMethod("GET");conn.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint, application/msword, */*");conn.setRequestProperty("Accept-Language", "zh-CN");conn.setRequestProperty("Referer", downloadUrl);conn.setRequestProperty("Charset","UTF-8");conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR2.0.50727; .NET CLR3.0.04506.30; .NET CLR3.0.4506.2152; .NET CLR 3.5.30729)");conn.setRequestProperty("Connection", "Keep-Alive");conn.connect();printResponseHeader(conn);if (conn.getResponseCode()==200) {this.fileSize =conn.getContentLength();//根据响应获取文件大小if (this.fileSize <= 0) throw new RuntimeException("Unkown file size ");String filename = getFileName(conn);this.saveFile = new File(fileSaveDir, filename);/* 保存文件 */Map<Integer, Integer> logdata = fileService.getData(downloadUrl);if(logdata.size()>0){for(Map.Entry<Integer, Integer> entry : logdata.entrySet())data.put(entry.getKey(),entry.getValue());}this.block = (this.fileSize %this.threads.length)==0? this.fileSize /this.threads.length : this.fileSize /this.threads.length + 1;if(this.data.size()==this.threads.length){for(int i = 0; i < this.threads.length; i++) {this.downloadSize +=this.data.get(i+1);}print("已经下载的长度"+this.downloadSize);}}else{throw new RuntimeException("server no response ");}} catch (Exception e) {print(e.toString());throw new RuntimeException("don't connection this url");}}/*** 获取文件名*/private String getFileName(HttpURLConnection conn) {String filename =this.downloadUrl.substring(stI ndexOf('/') + 1);if(filename==null ||"".equals(filename.trim())){//如果获取不到文件名称for (int i = 0;; i++) {String mine = conn.getHeaderField(i);if (mine == null) break;if("content-disposition".equals(conn.getHeader FieldKey(i).toLowerCase())){Matcher m =pile(".*filename=(.*)").matcher(mine.t oLowerCase());if(m.find()) return m.group(1);}}filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名}return filename;}/*** 开始下载文件* @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null* @return已下载文件大小* @throws Exception*/public intdownload(SmartDownloadProgressListener listener) throws Exception{try {RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rw");if(this.fileSize>0)randOut.setLength(this.fileSize);randOut.close();URL url = new URL(this.downloadUrl);if(this.data.size() !=this.threads.length){this.data.clear();//清除数据for (int i = 0; i < this.threads.length; i++) {this.data.put(i+1, 0);}}for(int i = 0; i < this.threads.length; i++) {int downLength = this.data.get(i+1);if(downLength < this.block &&this.downloadSize<this.fileSize){ //该线程未完成下载时,继续下载this.threads[i] = new SmartDownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1);this.threads[i].setPriority(7);this.threads[i].start();}else{this.threads[i] = null;}}this.fileService.save(this.downloadUrl, this.data);boolean notFinish = true;//下载未完成while (notFinish) {// 循环判断是否下载完毕Thread.sleep(900);notFinish = false;//假定下载完成for (int i = 0; i < this.threads.length; i++){if (this.threads[i] != null&& !this.threads[i].isFinish()) {notFinish = true;//下载没有完成if(this.threads[i].getDownLength() == -1){//如果下载失败,再重新下载this.threads[i] = new SmartDownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1);this.threads[i].setPriority(7);this.threads[i].start();}}}if(listener!=null)listener.onDownloadSize(this.downloadSize);}fileService.delete(this.downloadUrl);} catch (Exception e) {print(e.toString());throw new Exception("file download fail");}return this.downloadSize;}/*** 获取Http响应头字段* @param http* @return*/public static Map<String, String> getHttpResponseHeader(HttpURLConnection http) { Map<String, String> header = new LinkedHashMap<String, String>();for (int i = 0;; i++) {String mine = http.getHeaderField(i);if (mine == null) break;header.put(http.getHeaderFieldKey(i), mine);}return header;}/*** 打印Http头字段* @param http*/public static voidprintResponseHeader(HttpURLConnection http){ Map<String, String> header = getHttpResponseHeader(http);for(Map.Entry<String, String> entry : header.entrySet()){String key = entry.getKey()!=null ? entry.getKey()+ ":" : "";print(key+ entry.getValue());}}//打印日志private static void print(String msg){ Log.i(TAG, msg);}}4.2下载过程中的线程实现建立SmartDownloadThread类具体代码如下:package com.smart.impl;import java.io.File;import java.io.InputStream;import java.io.RandomAccessFile;import .HttpURLConnection;import .URL;import android.util.Log;public class SmartDownloadThread extends Thread { private static final String TAG = "SmartDownloadThread";private File saveFile;private URL downUrl;private int block;/* *下载开始位置 */private int threadId = -1;private int downLength;private boolean finish = false;private SmartFileDownloader downloader;public SmartDownloadThread(SmartFileDownloader downloader, URL downUrl, File saveFile, int block, int downLength, int threadId) {this.downUrl = downUrl;this.saveFile = saveFile;this.block = block;this.downloader = downloader;this.threadId = threadId;this.downLength = downLength;}@Overridepublic void run() {if(downLength < block){//未下载完成try {HttpURLConnection http = (HttpURLConnection) downUrl.openConnection();http.setConnectTimeout(5 * 1000);http.setRequestMethod("GET");http.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint, application/msword, */*");http.setRequestProperty("Accept-Language","zh-CN");http.setRequestProperty("Referer", downUrl.toString());http.setRequestProperty("Charset", "UTF-8");int startPos = block * (threadId - 1) + downLength;//开始位置int endPos = block * threadId -1;//结束位置http.setRequestProperty("Range","bytes=" + startPos + "-"+ endPos);//设置获取实体数据的范围http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR2.0.50727; .NET CLR3.0.04506.30; .NET CLR3.0.4506.2152; .NET CLR 3.5.30729)");http.setRequestProperty("Connection", "Keep-Alive");InputStream inStream =http.getInputStream();byte[] buffer = new byte[1024];int offset = 0;print("Thread "+ this.threadId+ " start download from position "+ startPos);RandomAccessFile threadfile = new RandomAccessFile(this.saveFile, "rwd");threadfile.seek(startPos);while((offset = inStream.read(buffer, 0, 1024)) != -1) {threadfile.write(buffer, 0, offset);downLength += offset;downloader.update(this.threadId, downLength);downloader.saveLogFile();downloader.append(offset);}threadfile.close();inStream.close();print("Thread " + this.threadId + " download finish");this.finish = true;} catch (Exception e) {this.downLength = -1;print("Thread "+ this.threadId+ ":"+ e);}}}private static void print(String msg){Log.i(TAG, msg);}/*** 下载是否完成* @return*/public boolean isFinish() {return finish;}/*** 已经下载的内容大小* @return如果返回值为-1,代表下载失败*/public long getDownLength() {return downLength;}}4.3 建立interface SmartDownloadProgressListener 侦听线程的下载进度代码如下:package com.smart.impl;public interface SmartDownloadProgressListener { public void onDownloadSize(int size);}5.建立activity 实现下载的触发,和界面的实时更新具体代码如下:package com.smart.activoty.download;import java.io.File;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;importcom.smart.impl.SmartDownloadProgressListener; import com.smart.impl.SmartFileDownloader;public class SmartDownloadActivity extends Activity {private ProgressBar downloadbar;private EditText pathText;private TextView resultView;private Handler handler = new Handler(){@Override//信息public void handleMessage(Message msg) { switch (msg.what) {case 1:int size = msg.getData().getInt("size");downloadbar.setProgress(size);float result =(float)downloadbar.getProgress()/(float)downloadbar.getMax();int p = (int)(result*100);resultView.setText(p+"%");if(downloadbar.getProgress()==downloadbar.getM ax())Toast.makeText(SmartDownloadActivity.this, R.string.success, 1).show();break;case -1:Toast.makeText(SmartDownloadActivity.this, R.string.error, 1).show();break;}}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);Button button =(Button)this.findViewById(R.id.button);downloadbar =(ProgressBar)this.findViewById(R.id.downloadbar); pathText =(EditText)this.findViewById(R.id.path);resultView =(TextView)this.findViewById(R.id.result);button.setOnClickListener(newView.OnClickListener() {@Overridepublic void onClick(View v) {String path =pathText.getText().toString();if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File dir =Environment.getExternalStorageDirectory();//文件保存目录download(path, dir);}else{Toast.makeText(SmartDownloadActivity.this,R.string.sdcarderror, 1).show();}}});}//对于UI控件的更新只能由主线程(UI线程)负责,如果在非UI 线程更新UI控件,更新的结果不会反映在屏幕上,某些控件还会出错private void download(final String path, final File dir){new Thread(new Runnable() {@Overridepublic void run() {try {SmartFileDownloader loader = new SmartFileDownloader(SmartDownloadActivity.this, path, dir, 3);int length = loader.getFileSize();//获取文件的长度downloadbar.setMax(length);loader.download(new SmartDownloadProgressListener(){@Overridepublic void onDownloadSize(int size) {//可以实时得到文件下载的长度Message msg = new Message();msg.what = 1;msg.getData().putInt("size", size);handler.sendMessage(msg);}});} catch (Exception e) {Message msg = new Message();//信息提示msg.what = -1;msg.getData().putString("error", "下载失败");//如果下载错误,显示提示失败!handler.sendMessage(msg);}}}).start();//开始}}6.到此为止运行会报错,因为没有向sdcard的协数据的权限,访问Internet的权限这需要在AndroidManifest.xml配置具体代码如下:<?xml version="1.0"encoding="utf-8"?><manifestxmlns:android="/apk/res /android"package="com.smart.activoty.download"android:versionCode="1"android:versionName="1.0"><application android:icon="@drawable/icon" android:label="@string/app_name"><activityandroid:name=".SmartDownloadActivity"android:label="@string/app_name"> <intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="UNCHER"/> </intent-filter></activity></application><uses-sdk android:minSdkVersion="8"/><!-- 访问internet权限 --><uses-permissionandroid:name="android.permission.INTERNET"/><!-- 在SDCard中创建与删除文件权限 --><uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FI LESYSTEMS"/><!-- 往SDCard写入数据权限 --><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_S TORAGE"/></manifest>。
http下载 原理
http下载原理
http下载的原理是通过客户端和服务器之间的通信来传输文件。
以下是具体的步骤:
1. 客户端发送一个请求给服务器,请求的内容包括文件的
URL和其他相关信息。
2. 服务器接收到请求后,查找请求的文件并准备发送给客户端。
3. 服务器将文件进行分割,每个分割部分称为一个数据包。
4. 服务器将每个数据包按照顺序打包,并使用TCP/IP协议将
这些数据包发送给客户端。
5. 客户端接收到数据包后,将其进行存储。
6. 客户端发送一个确认收到的消息给服务器,以便服务器知道数据包已经被成功接收。
7. 如果文件还没有完全传输,服务器继续发送剩下的数据包。
8. 客户端重复步骤5~7,直到所有的数据包都被接收。
9. 客户端将所有接收到的数据包重新组装成完整的文件。
10. 下载完成后,客户端可以使用该文件进行相关操作,如保
存到本地或进行后续处理。
整个http下载的过程是基于客户端和服务器之间的请求和响应,使用TCP/IP协议进行数据传输。
通过文件的分割和数据
包的传输,实现了大文件的高效下载。
idm断点续传原理
IDM断点续传原理1. 什么是IDM?IDM(Internet Download Manager)是一款功能强大的下载工具,它能够加速下载速度、支持断点续传、批量下载等功能。
其中,断点续传是IDM的一项重要功能,它能够在下载过程中出现意外中断时,从断点处继续下载,避免重新下载整个文件,节省时间和带宽。
2. IDM断点续传的基本原理IDM实现断点续传的基本原理是通过HTTP协议的Range请求头来实现的。
当我们在浏览器中下载一个文件时,浏览器会向服务器发送一个GET请求,服务器会返回整个文件的内容。
而在IDM中,它会发送一个带有Range请求头的GET请求,告诉服务器从指定的位置开始返回文件的内容。
具体来说,IDM的断点续传原理包括以下几个步骤:2.1 开始下载当用户在IDM中添加一个下载任务时,IDM会向服务器发送一个带有Range请求头的GET请求,请求下载文件的一部分内容。
2.2 服务器响应服务器接收到IDM的请求后,会根据请求头中的Range字段返回文件的一部分内容。
服务器会返回一个206 Partial Content的响应码,表示只返回部分内容。
2.3 下载文件的一部分IDM接收到服务器返回的文件内容后,会将其写入本地的临时文件中,同时记录已经下载的字节数。
2.4 暂停或中断下载在下载过程中,如果用户暂停或中断了下载任务,IDM会记录已经下载的字节数,并保存到一个临时文件中。
2.5 继续下载当用户重新开始下载时,IDM会读取之前保存的临时文件,获取已经下载的字节数,并向服务器发送带有Range请求头的GET请求,请求从上次下载的位置继续下载。
2.6 服务器继续响应服务器接收到IDM的请求后,会根据请求头中的Range字段返回文件剩余部分的内容。
2.7 下载剩余部分IDM接收到服务器返回的文件内容后,会将其追加写入之前的临时文件中,同时更新已经下载的字节数。
2.8 下载完成当整个文件都下载完成后,IDM会将临时文件重命名为最终的文件名,下载任务完成。
断点续传和多线程下载(上)
H T 蜘议简介 TP
下载 文件是 电皓与w E B服务器交互的过程 ,它们交互 的 “ 语 言 的专业名称是协议。传送文件的协议有多种,最常用的是 HTTP ( 超文本传输协设)和F P ( T 文件传送协议 ),我采用 ̄ HTTP 。
Ht l e tx ndRe e S qu  ̄
基本的下蠢过程
犏写下载程序 .可以直接 使用S c e 函数 ,但是这 要求开 发 ok t
人员理解 ,熟悉TC / P P I 执议。为 了简化I t r e 客 户端软件的开 nen t 发 ,Wi d ws n o 提供 了 套Wil e I 对常用的网络协议进行 了 一 n n t AP , 封装 ,把开 发I t ne 软件的 门槛 大太降低 了 我 们需要使用的 n e t r
I tn Ra tl 件 le e t Fe 读文 n r t d l
『t e leM d 美可It re旬辆 I e t o E nl nm Cs e ne nt
1
墨'
章 中难以垒 部阐 明 ,所 以 ,与 下载过 程关 系不 直接 的部 分基 本上
都忽 略 了 ,如异 常处理 和 尉络 错 误处 理等 ,敬请 各 位读 者注意 。 税使 用的开发环境是c ++ B i e 5 0 u l r . ,使用其他开发环 境或者 d 编 程 语 言的 腿友 请 自扦作适 当修 改 。 H t Ie R q e  ̄用h o c ̄ t fp n e us i t Cr t m ̄ 柄,定义为h q  ̄t Re u 。
体的 函数原型请 参考M S 。 DN 在使 用这些 函数时 ,必 须 严格 区分它
下载 中断 ,在 重新建 立连 接后 ,跳 过 已经下 载的部 丹 ,而 只下载
CommonViews_Introduction
ThinkAndroid简介ThinkAndroid是一个免费的开源的、简易的、遵循Apache2开源协议发布的Android开发框架,其开发宗旨是简单、快速的进行Android应用程序的开发,包含Android mvc、简易sqlite orm、ioc模块、封装Android httpclitent的http模块,具有快速构建文件缓存功能,无需考虑缓存文件的格式,都可以非常轻松的实现缓存,它还基于文件缓存模块实现了图片缓存功能,在android中加载的图片的时候,对oom的问题,和对加载图片错位的问题都轻易解决。
他还包括了一个手机开发中经常应用的实用工具类,如日志管理,配置文件管理,android下载器模块,网络切换检测等等工具。
目前ThinkAndroid主要有以下模块:∙MVC模块:实现视图与模型的分离。
∙ioc模块:android中的ioc模块,完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。
∙数据库模块:android中的orm框架,使用了线程池对sqlite进行操作。
∙http模块:通过httpclient进行封装http数据请求,支持异步及同步方式加载。
∙缓存模块:通过简单的配置及设计可以很好的实现缓存,对缓存可以随意的配置∙图片缓存模块:imageview加载图片的时候无需考虑图片加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。
∙配置器模块:可以对简易的实现配对配置的操作,目前配置文件可以支持Preference、Properties对配置进行存取。
∙日志打印模块:可以较快的轻易的是实现日志打印,支持日志打印的扩展,目前支持对sdcard写入本地打印、以及控制台打印∙下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。
∙网络状态检测模块:当网络状态改变时,对其进行检测。
xUtils简介xUtils 包含了很多实用的android工具。
移动应用开发技术中的断点续传功能实现方法
移动应用开发技术中的断点续传功能实现方法随着移动应用的迅速发展,用户对于应用的要求也越来越高。
其中,断点续传功能成为了很多应用的必备特性之一。
断点续传功能可以在文件传输过程中,当网络出现问题或者用户主动暂停传输时,能够记录传输的进度并在网络恢复或者用户重新启动传输时自动从上次的断点处继续传输,提升用户体验。
在移动应用开发技术中,实现断点续传功能有许多方法和技术。
一、分片上传分片上传是实现断点续传功能的一种常见方法。
这种方法将文件切割成多个较小的片段,在上传的过程中,每传输完成一个片段,在服务器端都能保留下来。
如果在传输过程中出现了中断,下次再次发起上传请求时,服务器会根据已经传输完成的片段信息来判断上次传输的进度,并继续传输下一个未完成的片段。
这种方法实现起来相对简单,而且适用于各种类型的文件传输。
二、断点标记使用断点标记也是常见的断点续传实现方法之一。
在传输过程中,可以将每个传输的片段的字节数和传输进度等信息记录下来。
下次再次发起传输请求时,可以通过读取这些标记信息来判断上次传输的进度,并从断点处继续传输。
这种方法比较灵活,可以适用于各种传输方式,但需要服务器端和客户端之间进行相应的状态记录和交互。
三、使用断点恢复库移动应用开发中有一些成熟的断点续传库可以使用,例如Android平台上的"AndroidResumableUpload"库。
这些库提供了一系列的API和功能,能够方便地实现断点续传功能。
通过这些库,我们可以简单地调用相应的接口来实现文件的断点续传。
这种方法省去了开发者自己去实现断点续传的繁琐工作,提高了开发效率。
四、断点续传策略除了实现方法之外,制定合适的断点续传策略也是非常重要的。
在断点续传过程中,如何合理地选择和配置断点参数,以及如何应对各种特殊情况都需要仔细考虑。
例如,可以通过设置最大传输速度、最大传输片段数以及传输超时时间等参数来优化传输效率并避免网络拥堵。
网络断点续传软件使用技巧大揭秘
网络断点续传软件使用技巧大揭秘一、网络断点续传软件的概念与作用网络断点续传软件是一种可以在网络传输过程中出现断点时,能够恢复传输而不需要重新开始的工具。
它的主要作用是提高文件传输的效率和稳定性,特别适用于大文件的传输过程中。
网络传输过程中,如果由于网络不稳定等原因造成传输中断,传统的方式是重新开始传输,这会很耗费时间和精力。
而断点续传软件可以在传输中断后,从上一次中断的地方继续传输,节省了传输时间,并且有效降低了传输失败的概率。
二、网络断点续传软件的选择与下载1. 查找评价较好的软件在选择网络断点续传软件时,首先要关注用户的评价。
可以通过在各大软件下载网站搜索相关软件,并查看用户的评价和反馈。
选择评价较好的软件,可以避免一些常见问题和不稳定性。
2. 软件下载及安装下载网络断点续传软件最好选择正规的软件官网或者知名的软件下载站点,确保软件的安全性。
下载后,按照软件的安装步骤进行软件安装,注意不要随意点击其他附带软件,以免给电脑带来不必要的麻烦。
三、网络断点续传软件的基本设置1. 设置下载路径在使用断点续传软件之前,首先需要设置下载路径。
点击软件的设置选项,根据个人需求选择下载路径,并设置好保存文件的命名规则和目录结构,方便管理和查找。
2. 设置最大同时下载数为了避免浪费网络资源以及文件传输时间过长,可以适当设置最大同时下载数。
通常来说,同时下载数不能过多或者过少,最好根据自己的网络状况和计算机配置进行合理设置。
四、网络断点续传软件的使用技巧1. 下载链接的获取要使用网络断点续传软件下载文件,需要先获取下载链接。
在浏览器中打开需要下载的文件,右键点击文件链接,选择复制链接地址,然后在断点续传软件的下载界面粘贴链接地址。
2. 任务添加与管理在软件的下载界面,粘贴好下载链接后,点击添加任务按钮。
软件会自动解析链接,并显示文件的基本信息和下载大小等。
可以根据个人需求设置下载任务的优先级、队列顺序等。
3. 下载限速当你需要在有限的网络带宽下进行下载时,可以设置下载的限制速度。
http下载协议
http下载协议HTTP(Hypertext Transfer Protocol)是一种被广泛应用于万维网(World Wide Web)的协议,用于在计算机网络中传输超文本文档的应用层协议。
在HTTP协议中,客户端向服务器发送请求,服务器根据请求返回相应的内容,实现了客户端与服务器之间的通信。
HTTP的下载功能是其最常用的功能之一。
通过HTTP下载,用户可以从服务器上获取所需的文件,如图片、音频、视频等。
HTTP下载协议的操作非常简单,只需要通过HTTP请求向服务器发送一个GET请求,然后服务器将文件以字节流的形式返回给客户端。
HTTP下载协议的具体流程如下:1. 客户端发起下载请求:客户端将文件的URL发送给服务器,请求下载文件。
2. 服务器响应请求:服务器接收到下载请求后,检查请求的文件是否存在,如果存在则返回一个HTTP响应,状态码为200(表示成功)。
3. 建立连接:客户端与服务器之间建立TCP连接,以便进行文件的传输。
4. 下载文件:服务器将文件以字节流的形式通过TCP连接发送给客户端,客户端接收到文件数据后保存到本地磁盘。
在HTTP下载协议中,还可以使用一些可选的请求头字段来控制文件的下载行为。
例如:- Range:可以指定下载文件的起始位置和结束位置,实现下载文件的分块下载。
- If-Modified-Since:能够实现断点续传的功能,指定下载文件的修改时间,服务器会检查文件的修改时间,如果没有变化则返回304,客户端可以使用已经下载的部分文件进行断点续传。
值得注意的是,HTTP协议本身不提供下载速度的限制机制。
如果需要限制下载速度,可以通过一些其他的手段来实现,如在服务器端进行限制或者使用下载工具进行限速。
总结起来,HTTP下载协议是一种简单而有效的协议,通过客户端向服务器发送请求,服务器返回文件数据,实现了文件的下载功能。
同时,通过一些可选的请求头字段,可以实现更多的功能,如文件的分块下载和断点续传等。
移动应用中的文件上传与下载功能实现方法
移动应用中的文件上传与下载功能实现方法随着智能手机的普及和移动应用的兴起,越来越多的应用程序需要实现文件上传和下载功能。
无论是发送电子邮件附件、上传照片到社交媒体,还是下载音乐、视频等媒体文件,这些功能都离不开文件的上传和下载。
那么,如何在移动应用中实现这些功能呢?本文将简要扼要地介绍一些常用的方法和技术,帮助开发者了解文件上传和下载功能的实现过程。
一、文件上传功能的实现1. 选择适当的服务器后端技术要实现文件上传功能,首先需要选择一种适合的服务器端技术来处理上传的文件。
常见的服务器端技术包括PHP、Node.js、Java等。
每种技术都有其优缺点,开发者可以根据自己的需求和技术背景选择适合的技术。
2. 构建文件上传接口在服务器端,需要构建一个文件上传接口,用于接受客户端上传的文件。
开发者可以使用各种Web框架来构建这个接口,如Express.js、Spring MVC等。
在接口中,需要对上传的文件进行校验和处理,如检查文件类型、大小限制等。
一般来说,服务器端会将上传的文件保存到特定的目录中,或者将文件存储到云存储服务中。
3. 实现客户端文件上传功能在移动应用中,需要实现一个文件上传的功能模块。
开发者可以使用系统提供的文件选择器,让用户选择要上传的文件。
接着,将选择的文件通过HTTP或其他协议发送给服务器端接口。
在上传过程中,需要显示上传进度条,以便用户可以实时了解上传进度。
二、文件下载功能的实现1. 构建文件下载接口与文件上传功能类似,文件下载功能也需要在服务器端构建一个文件下载接口。
该接口会接收来自客户端的下载请求,并根据请求参数返回相应的文件。
在服务器端,可以使用诸如Express.js、Flask等框架来构建这个接口,并设置相应的路由规则。
2. 实现客户端文件下载功能在移动应用中,可以使用系统提供的下载器组件来实现文件下载功能。
开发者可以在应用中提供一个文件下载模块,用户可以输入下载链接或点击应用中的下载按钮来发起下载请求。
android中实现OkHttp下载文件并带进度条
android中实现OkHttp下载⽂件并带进度条OkHttp是⽐较⽕的⽹络框架,它⽀持同步与异步请求,⽀持缓存,可以拦截,更⽅便下载⼤⽂件与上传⽂件的操作。
下⾯我们⽤OkHttp来下载⽂件并带进度条!相关资料:⼀、服务器端简单搭建可以参考这篇⽂章。
新建项⽬OkHttpServer,在WebContent⽬录下新建downloadfile⽬录,将要下载的jpg⽂件放在项⽬下。
如下图:⼆、Android端下⾯我们进⼊正题。
1.build.gradle的dependencies配置如下compile 'com.android.support:appcompat-v7:24.1.1'compile 'com.squareup.okhttp3:okhttp:3.2.0'compile 'com.squareup.okio:okio:1.7.0'2.activity_main.xml<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.huang.myokhttp.MainActivity"><Buttonandroid:id="@+id/ok_download"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="下载⽂件" /><TextViewandroid:id="@+id/download_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="0" /><ProgressBarandroid:id="@+id/download_progress"style="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="100" /></RelativeLayout>3.编写OkHttpUtil如下:private static OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10000, LISECONDS).readTimeout(10000,LISECONDS).writeTimeout(10000,LISECONDS).build();//下载⽂件⽅法public static void downloadFile(String url, final ProgressListener listener, Callback callback){//增加拦截器OkHttpClient client = okHttpClient.newBuilder().addNetworkInterceptor(new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Response response = chain.proceed(chain.request());return response.newBuilder().body(new ProgressResponseBody(response.body(),listener)).build();}}).build();Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(callback);}4.上⾯代码中的ProgressResponseBody是⾃⼰编写的类,ProgressListener 是监听的接⼝:ProgressListener 接⼝public interface ProgressListener {//已完成的总的⽂件长度是否完成void onProgress(long currentBytes, long contentLength, boolean done);}ProgressResponseBody继承ResponseBody ,返回监听进度public class ProgressResponseBody extends ResponseBody {public static final int UPDATE = 0x01;public static final String TAG = ProgressResponseBody.class.getName();private ResponseBody responseBody;private ProgressListener mListener;private BufferedSource bufferedSource;private Handler myHandler;public ProgressResponseBody(ResponseBody body, ProgressListener listener) {responseBody = body;mListener = listener;if (myHandler==null){myHandler = new MyHandler();}}/*** 将进度放到主线程中显⽰*/class MyHandler extends Handler {public MyHandler() {super(Looper.getMainLooper());}@Overridepublic void handleMessage(Message msg) {switch (msg.what){case UPDATE:ProgressModel progressModel = (ProgressModel) msg.obj;//接⼝返回if (mListener!=null)mListener.onProgress(progressModel.getCurrentBytes(),progressModel.getContentLength(),progressModel.isDone()); break;}}}@Overridepublic MediaType contentType() {return responseBody.contentType();}@Overridepublic long contentLength() {return responseBody.contentLength();}@Overridepublic BufferedSource source() {if (bufferedSource==null){bufferedSource = Okio.buffer(mySource(responseBody.source()));}return bufferedSource;}private Source mySource(Source source) {return new ForwardingSource(source) {long totalBytesRead = 0L;@Overridepublic long read(Buffer sink, long byteCount) throws IOException {long bytesRead = super.read(sink, byteCount);totalBytesRead +=bytesRead!=-1?bytesRead:0;//发送消息到主线程,ProgressModel为⾃定义实体类Message msg = Message.obtain();msg.what = UPDATE;msg.obj = new ProgressModel(totalBytesRead,contentLength(),totalBytesRead==contentLength());myHandler.sendMessage(msg);return bytesRead;}};}}5.MainActivity的代码:public class MainActivity extends AppCompatActivity implements View.OnClickListener{public static final String TAG = MainActivity.class.getName();private ProgressBar download_progress;private TextView download_text;public static String basePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/okhttp";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);download_progress = (ProgressBar) findViewById(R.id.download_progress);download_text = (TextView) findViewById(R.id.download_text);findViewById(R.id.ok_download).setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()){case R.id.ok_download:String url = "http://192.168.0.104:8080/OkHttpServer/download/2.jpg";final String fileName = url.split("/")[url.split("/").length - 1];Log.i(TAG, "fileName==" + fileName);OkHttpUtil.downloadFile(url, new ProgressListener() {@Overridepublic void onProgress(long currentBytes, long contentLength, boolean done) {Log.i(TAG, "currentBytes==" + currentBytes + "==contentLength==" + contentLength + "==done==" + done); int progress = (int) (currentBytes * 100 / contentLength);download_progress.setProgress(progress);download_text.setText(progress + "%");}}, new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null) {InputStream is = response.body().byteStream();FileOutputStream fos = new FileOutputStream(new File(basePath + "/" + fileName)); int len = 0;byte[] buffer = new byte[2048];while (-1 != (len = is.read(buffer))) {fos.write(buffer, 0, len);}fos.flush();fos.close();is.close();}}});break;}}}6.最后不要忘了添加权限:<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
网络下载的原理
网络下载的原理网络下载是指将远程服务器上的文件或数据传输到本地设备的过程。
从技术上讲,网络下载包括从服务器上获取文件的请求、服务器响应和数据传输三个主要步骤。
在这个过程中,涉及到各种协议、网络技术和算法,以实现高效、安全和可靠的下载。
首先,网络下载的第一步是请求。
当用户点击下载链接或输入下载地址时,设备(一般是个人电脑、智能手机等)需要向服务器发送请求,以获取要下载的文件。
这个请求使用的协议通常是HTTP或HTTPS。
在这个请求中,会包含文件的URL、用户设备的信息,甚至还可能包含下载文件的一些附加参数,如文件块大小、下载速度限制等。
这些参数可以提高下载的效率和用户体验。
接下来,服务器会收到这个请求,并根据请求的内容进行处理。
服务器会检查请求中的URL和用户设备的信息,以确定是否允许下载,并检查服务器上是否存在要下载的文件。
如果一切正常,服务器则会返回一个响应给用户设备。
响应中包含了服务器返回给用户设备的数据,以及一些其他的信息,如文件大小、内容类型、响应码等。
在HTTP协议中,响应码表示了服务器对请求的处理结果,例如200代表请求成功,404代表资源未找到,500代表服务器内部错误等。
响应还包含了时间戳、缓存策略等相关信息,用于优化下载的速度和用户体验。
接下来,设备需要根据响应中的数据来下载文件。
下载文件的具体方式取决于服务器和设备之间的通信协议。
常见的下载方式有两种:直接下载和分段下载。
直接下载是指设备从服务器上连接,请求整个文件,并将文件一次性下载到本地设备。
这种方式适用于小型文件和带宽较大的网络环境,它可以快速下载文件,但会占用较多的带宽资源。
在直接下载中,设备和服务器之间的传输一般通过TCP/IP协议进行,确保数据的可靠传输。
分段下载是指将文件分成多个固定大小的块,设备分批次下载这些块,并在下载完成后将它们合并成完整的文件。
这种方式适用于大型文件和带宽较小的网络环境,它可以在网络不稳定的情况下保证下载的可靠性和续传功能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
0.使用多线程下载会提升文件下载的速度,那么多线程下载文件的过程是:(1)首先获得下载文件的长度,然后设置本地文件的长度HttpURLConnection.getContentLength();RandomAccessFile file = new RandomAccessFile("QQWubiSetup.exe","rwd");file.setLength(filesize);//设置本地文件的长度(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示。
例如10M大小,使用3个线程来下载,线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M下载开始位置:线程id*每条线程下载的数据长度 = ?下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止代码如下:HttpURLConnection.setRequestProperty("Range","bytes=2097152-4194303");(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");threadfile.seek(2097152);//从文件的什么位置开始写入数据1.多线程下载的核心代码示例Java代码1.public class MulThreadDownload2.{3. /**4. * 多线程下载5. * @param args6. */7. public static void main(String[] args)8. {9. String path = "/QQWubiSetup.exe";10. try11. {12. new MulThreadDownload().download(path, 3);13. }14. catch (Exception e)15. {16. e.printStackTrace();17. }18. }19. /**20. * 从路径中获取文件名称21. * @param path 下载路径22. * @return23. */24. public static String getFilename(String path)25. {26. return path.substring(stIndexOf('/')+1);27. }28. /**29. * 下载文件30. * @param path 下载路径31. * @param threadsize 线程数32. */33. public void download(String path, int threadsize) throwsException34. {35. URL url = new URL(path);36. HttpURLConnection conn = (HttpURLConnection)url.openConnection();37. conn.setRequestMethod("GET");38. conn.setConnectTimeout(5 * 1000);39. //获取要下载的文件的长度40. int filelength = conn.getContentLength();41. //从路径中获取文件名称42. String filename = getFilename(path);43. File saveFile = new File(filename);44. RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd");45. //设置本地文件的长度和下载文件相同46. accessFile.setLength(filelength);47. accessFile.close();48. //计算每条线程下载的数据长度49. int block = filelength%threadsize==0? filelength/threadsize : filelength/threadsize+1;50. for(int threadid=0 ; threadid < threadsize ; threadid++){51. new DownloadThread(url, saveFile, block, threadid).start();52. }53. }54.55. private final class DownloadThread extends Thread56. {57. private URL url;58. private File saveFile;59. private int block;//每条线程下载的数据长度60. private int threadid;//线程id61. public DownloadThread(URL url, File saveFile, int block, int threadid)62. {63. this.url = url;64. this.saveFile = saveFile;65. this.block = block;66. this.threadid = threadid;67. }68.@Override69. public void run()70. {71. //计算开始位置公式:线程id*每条线程下载的数据长度= ?72. //计算结束位置公式:(线程id +1)*每条线程下载的数据长度-1 =?73. int startposition = threadid * block;74. int endposition = (threadid + 1 ) * block - 1;75. try76. {77. RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd");78. //设置从什么位置开始写入数据79. accessFile.seek(startposition);80. HttpURLConnection conn = (HttpURLConnection)url.openConnection();81. conn.setRequestMethod("GET");82. conn.setConnectTimeout(5 * 1000);83. conn.setRequestProperty("Range", "bytes="+ startposition+ "-"+ endposition);84. InputStream inStream = conn.getInputStream();85. byte[] buffer = new byte[1024];86. int len = 0;87. while( (len=inStream.read(buffer)) != -1 )88. {89. accessFile.write(buffer, 0, len);90. }91. inStream.close();92. accessFile.close();93. System.out.println("线程id:"+ threadid+ "下载完成");94. }95. catch (Exception e)96. {97. e.printStackTrace();98. }99. }100. }101.}2.多线程断点下载功能,这里把断点数据保存到数据库中:注意代码注释的理解(0)主Activity,关键点使用Handler更新进度条与开启线程下载避免ANR若不使用Handler却要立即更新进度条数据,可使用://resultView.invalidate(); UI线程中立即更新进度条方法//resultView.postInvalidate(); 非UI线程中立即更新进度条方法Java代码1./**2. * 注意这里的设计思路,UI线程与参数保存问题,避免ANR问题,UI控件的显示3. * @author kay4. *5. */6.public class DownloadActivity extends Activity7.{8. private EditText downloadpathText;9. private TextView resultView;10. private ProgressBar progressBar;11.12.@Override13. public void onCreate(Bundle savedInstanceState)14. {15. super.onCreate(savedInstanceState);16. setContentView(yout.main);17.18. downloadpathText = (EditText) this.findViewById(R.id.downloadpath);19. progressBar = (ProgressBar) this.findViewById(R.id.downloadbar);20. resultView = (TextView) this.findViewById(R.id.result);21. Button button = (Button) this.findViewById(R.id.button);22. button.setOnClickListener(new View.OnClickListener()23. {24.@Override25. public void onClick(View v)26. {27. //取得下载路径28. String path = downloadpathText.getText().toString();29. //判断SDCard是否存在30. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))31. {32. //下载操作33. download(path, Environment.getExternalStorageDirectory());34. }35. else36. {37. Toast.makeText(DownloadActivity.this, R.string.sdcarderror, 1).show();38. }39. }40. });41. }42. //主线程(UI线程)43. //业务逻辑正确,但是该程序运行的时候有问题(可能出现ANR问题)44. //对于显示控件的界面更新只是由UI线程负责,如果是在非UI线程更新控件的属性值,更新后的显示界面不会反映到屏幕上45. /**46. * 参数类型:因为启动一个线程还需要使用到上面方法的参数,而主方法启动后很快就会销毁,47. * 那么使用Final可以解决参数丢失的问题48. * path 注意是Final类型49. * savedir 注意是Final类型50. */51. private void download(final String path, final File savedir)52. {53. //这里开启一个线程避免ANR错误54. new Thread(new Runnable()55. {56.@Override57. public void run()58. {59. FileDownloader loader = new FileDownloader(DownloadActivity.this, path, savedir, 3);60. //设置进度条的最大刻度为文件的长度61. progressBar.setMax(loader.getFileSize());62. try63. {64. loader.download(new DownloadProgressListener()65. {66. /**67. * 注意这里的设计,显示进度条数据需要使用Handler来处理68. * 因为非UI线程更新后的数据不能被刷新69. */70.@Override71. public void onDownloadSize(int size)72. {73. //实时获知文件已经下载的数据长度74. Message msg = new Message();75. //设置消息标签76. msg.what = 1;77. msg.getData().putInt("size", size);78. //使用Handler对象发送消息79. handler.sendMessage(msg);80. }81. });82. }83. catch (Exception e)84. {85. //发送一个空消息到消息队列86. handler.obtainMessage(-1).sendToTarget();87. /**88. * 或者使用下面的方法发送一个空消息89. * Message msg = new Message();90. * msg.what = 1;91. * handler.sendMessage(msg);92. */93. }94. }95. }).start();96. }97.98.99. /**Handler原理:当Handler被创建时会关联到创建它的当前线程的消息队列,该类用于往消息队列发送消息100. *101. * 消息队列中的消息由当前线程内部进行处理102. */103. private Handler handler = new Handler()104. {105. //重写Handler里面的handleMessage方法处理消息106.@Override107. public void handleMessage(Message msg)108. {109. switch (msg.what)110. {111. case 1:112. //进度条显示113. progressBar.setProgress(msg.getData().getInt("size"));114. float num = (float)progressBar.getProg ress()/(float)progressBar.getMax();115. int result = (int)(num*100);116. //resultView.invalidate(); UI线程中立即更新进度条方法117. //resultView.postInvalidate(); 非UI线程中立即更新进度条方法118. resultView.setText(result+ "%"); 119. //判断是否下载成功120. if(progressBar.getProgress()==progress Bar.getMax())121. {122. Toast.makeText(DownloadActivity.th is, R.string.success, 1).show();123. }124. break;125. case -1:126. Toast.makeText(DownloadActivity.this, R.string.error, 1).show();127. break;128. }129. }130. };131.132.}(1)下载类:注意计算每条线程的下载长度与下载起始位置的方法Java代码1.public class DownloadThread extends Thread2.{3. private static final String TAG = "DownloadThread";4. private File saveFile;5. private URL downUrl;6. private int block;7. //下载开始位置8. private int threadId = -1;9. //下载文件长度10. private int downLength;11. private boolean finish = false;12. private FileDownloader downloader;13. public DownloadThread(FileDownloader downloader, URL downUrl, File saveFile, int block, int downLength, int threadId)14. {15. this.downUrl = downUrl;16. this.saveFile = saveFile;17. this.block = block;18. this.downloader = downloader;19. this.threadId = threadId;20. this.downLength = downLength;21. }22.23.@Override24. public void run()25. {26. //未下载完成27. if(downLength < block)28. {29. try30. {31. HttpURLConnection http = (HttpURLConnection)downUrl.openConnection();32. http.setConnectTimeout(5 * 1000);33. http.setRequestMethod("GET");34. http.setRequestProperty("Accept", "image/gif,image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave -flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, applicati on/vnd.ms-excel, application/vnd.ms-powerpoint, application/ms word, */*");35. http.setRequestProperty("Accept-Language", "zh-CN");36. http.setRequestProperty("Referer", downUrl.toString());37. http.setRequestProperty("Charset", "UTF-8");38. //下载开始位置:线程id*每条线程下载的数据长度 = ?39. int startPos = block * (threadId - 1) + downLength;40. //下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?41. int endPos = block * threadId -1;42. //设置获取实体数据的范围43. http.setRequestProperty("Range", "bytes=" + startPos + "-"+ endPos);44. http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");45. http.setRequestProperty("Connection", "Keep-Alive");46.47. InputStream inStream = http.getInputStream();48. byte[] buffer = new byte[1024];49. int offset = 0;50. print("Thread " + this.threadId + " start download from position "+ startPos);51. RandomAccessFile threadfile = new RandomAccessFile(this.saveFile, "rwd");52. threadfile.seek(startPos);53. while ((offset = inStream.read(buffer, 0, 1024)) != -1)54. {55. threadfile.write(buffer, 0, offset);56. downLength += offset;57. downloader.update(this.threadId, downLength);58. downloader.append(offset);59. }60. threadfile.close();61. inStream.close();62. print("Thread " + this.threadId + " downloadfinish");63. //标记是否完成64. this.finish = true;65. }66. catch (Exception e)67. {68. this.downLength = -1;69. print("Thread "+ this.threadId+ ":"+ e);70. }71. }72. }73.74. private static void print(String msg)75. {76. Log.i(TAG, msg);77. }78.79. /**80. * 下载是否完成81. * @return82. */83. public boolean isFinish()84. {85. return finish;86. }87.88. /**89. * 已经下载的内容大小90. * @return 如果返回值为-1,代表下载失败91. */92. public long getDownLength()93. {94. return downLength;95. }96.}文件下载器,使用Java代码1./**2. * 文件下载器,使用这个类的方法如下示例:3. * FileDownloader loader = new FileDownloader(context, "http:///ejb3/ActivePort.exe",4. * new File("D:\\androidsoft\\test"), 2);5. * loader.getFileSize();//得到文件总大小6. * try {7. * loader.download(new DownloadProgressListener(){8. * public void onDownloadSize(int size) {9. * print("已经下载:"+ size);10. * }11. * });12. * }13. * catch (Exception e)14. * {15. * e.printStackTrace();16. * }17. */18.public class FileDownloader19.{20. private static final String TAG = "FileDownloader";21. private Context context;22. private FileService fileService;23. //已下载文件长度24. private int downloadSize = 0;25. //原始文件长度26. private int fileSize = 0;27. ///线程数28. private DownloadThread[] threads;29. //本地保存文件30. private File saveFile;31. //缓存各线程下载的长度32. private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>();33. //每条线程下载的长度34. private int block;35. //下载路径36. private String downloadUrl;37. //获取线程数38. public int getThreadSize()39. {40. return threads.length;41. }42. /**43. * 获取文件大小44. * @return45. */46. public int getFileSize()47. {48. return fileSize;49. }50. /**51. * 累计已下载大小52. * @param size53. */54. protected synchronized void append(int size)55. {56. downloadSize += size;57. }58. /**59. * 更新指定线程最后下载的位置60. * @param threadId 线程id61. * @param pos 最后下载的位置62. */63. protected synchronized void update(int threadId, int pos)64. {65. this.data.put(threadId, pos);66. this.fileService.update(this.downloadUrl, this.data);67. }68. /**69. * 文件下载构造器70. * @param downloadUrl 下载路径71. * @param fileSaveDir 文件保存目录72. * @param threadNum 下载线程数73. */74. public FileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum)75. {76. try77. {78. this.context = context;79. this.downloadUrl = downloadUrl;80. fileService = new FileService(this.context);81. URL url = new URL(this.downloadUrl);82. if(!fileSaveDir.exists()) fileSaveDir.mkdirs();83. this.threads = new DownloadThread[threadNum];84. HttpURLConnection conn = (HttpURLConnection) url.openConnection();85. conn.setConnectTimeout(5*1000);86. conn.setRequestMethod("GET");87. conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-fla sh, application/xaml+xml, application/vnd.ms-xpsdocument, appl ication/x-ms-xbap, application/x-ms-application, application/v nd.ms-excel, application/vnd.ms-powerpoint, application/msword , */*");88. conn.setRequestProperty("Accept-Language", "zh-CN");89. conn.setRequestProperty("Referer", downloadUrl);90. conn.setRequestProperty("Charset", "UTF-8");91. conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR1.1.4322; .NET CLR2.0.50727; .NET CLR3.0.04506.30; .NET CLR3.0.4506.2152; .NET CLR 3.5.30729)");92. conn.setRequestProperty("Connection", "Keep-Alive");93. conn.connect();94. printResponseHeader(conn);95. if (conn.getResponseCode()==200)96. {97. //根据响应获取文件大小98. this.fileSize = conn.getContentLength();99. if (this.fileSize <= 0) throw new RuntimeException("Unkown file size ");100. //获取文件名称101. String filename = getFileName(conn); 102. //构建保存文件103. this.saveFile = new File(fileSaveDir, file name);104. //获取下载记录105. Map<Integer, Integer> logdata = fileService.getData(downloadUrl);106. //如果存在下载记录107. if(logdata.size()>0)108. {109. //把各条线程已经下载的数据长度放入data 中110. for(Map.Entry<Integer, Integer> entry : logdata.entrySet())111. data.put(entry.getKey(), entry.get Value());112. }113. //下面计算所有线程已经下载的数据长度114. if(this.data.size()==this.threads.length)115. {116. for (int i = 0; i < this.threads.lengt h; i++)117. {118. this.downloadSize += this.data.get (i+1);119. }120. print("已经下载的长度"+ this.downloadSize);121. }122. //计算每条线程下载的数据长度123. this.block = (this.fileSize % this.threads .length)==0? this.fileSize / this.threads.length : this.fileSi ze / this.threads.length + 1;124. }125. else126. {127. throw new RuntimeException("server no resp onse ");128. }129. }130. catch (Exception e)131. {132. print(e.toString());133. throw new RuntimeException("don't connection t his url");134. }135. }136. /**137. * 获取文件名138. */139. private String getFileName(HttpURLConnection conn) 140. {141. String filename = this.downloadUrl.substring(this.stIndexOf('/') + 1);142. if(filename==null || "".equals(filename.trim())){/ /如果获取不到文件名称143. for (int i = 0;; i++) {144. String mine = conn.getHeaderField(i); 145. if (mine == null) break;146. if("content-disposition".equals(conn.getHe aderFieldKey(i).toLowerCase())){147. Matcher m = pile(".*filenam e=(.*)").matcher(mine.toLowerCase());148. if(m.find()) return m.group(1); 149. }150. }151. filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名152. }153. return filename;154. }155.156. /**157. * 开始下载文件158. * @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null159. * @return 已下载文件大小160. * @throws Exception161. */162. public int download(DownloadProgressListener listener) throws Exception{163. try164. {165. //创建本地文件166. RandomAccessFile randOut = new RandomAccessFil e(this.saveFile, "rw");167. if(this.fileSize>0) randOut.setLength(this.fil eSize);168. randOut.close();169. URL url = new URL(this.downloadUrl);170. if(this.data.size() != this.threads.length) 171. {172. this.data.clear();173. for (int i = 0; i < this.threads.length; i ++)174. {175. //初始化每条线程已经下载的数据长度为176. this.data.put(i+1, 0);177. }178. }179. //开启线程进行下载180. for (int i = 0; i < this.threads.length; i++)181. {182. int downLength = this.data.get(i+1); 183. //判断线程是否已经完成下载,否则继续下载184. if(downLength < this.block && this.downloa dSize<this.fileSize)185. {186. this.threads[i] = new DownloadThread(t his, url, this.saveFile, this.block, this.data.get(i+1), i+1);187. this.threads[i].setPriority(7);//可删除这条188. this.threads[i].start();189. }190. else191. {192. this.threads[i] = null;193. }194. }195. this.fileService.save(this.downloadUrl, this.d ata);196. //下载未完成197. boolean notFinish = true;198. // 循环判断所有线程是否完成下载199. while (notFinish)200. {201. Thread.sleep(900);202. //假定全部线程下载完成203. notFinish = false;204. for (int i = 0; i < this.threads.length; i ++)205. {206. //如果发现线程未完成下载207. if (this.threads[i] != null && !this.t hreads[i].isFinish())208. {209. //设置标志为下载没有完成210. notFinish = true;211. //如果下载失败,再重新下载212. if(this.threads[i].getDownLength() == -1)213. {214. this.threads[i] = new Download Thread(this, url, this.saveFile, this.block, this.data.get(i+1 ), i+1);215. this.threads[i].setPriority(7) ;216. this.threads[i].start(); 217. }218. }219. }220. //通知目前已经下载完成的数据长度221. if(listener!=null) listener.onDownloadSize (this.downloadSize);222. }223. //删除数据库中下载信息224. fileService.delete(this.downloadUrl);225. }226. catch (Exception e)227. {228. print(e.toString());229. throw new Exception("file download fail"); 230. }231. return this.downloadSize;232. }233.234. /**235. * 获取Http响应头字段236. * @param http237. * @return238. */239. public static Map<String, String> getHttpResponseHeade r(HttpURLConnection http) {240. Map<String, String> header = new LinkedHashMap<Str ing, String>();241. for (int i = 0;; i++) {242. String mine = http.getHeaderField(i); 243. if (mine == null) break;244. header.put(http.getHeaderFieldKey(i), mine);245. }246. return header;247. }248. /**249. * 打印Http头字段250. * @param http251. */252. public static void printResponseHeader(HttpURLConnecti on http)253. {254. Map<String, String> header = getHttpResponseHeader (http);255. for(Map.Entry<String, String> entry : header.entry Set())256. {257. String key = entry.getKey()!=null ? entry.getK ey()+ ":" : "";258. print(key+ entry.getValue());259. }260. }261. private static void print(String msg)262. {263. Log.i(TAG, msg);264. }265.}Java代码1.public interface DownloadProgressListener2.{3. public void onDownloadSize(int size);4.}(2)文件操作,断点数据库存储Java代码1.public class DBOpenHelper extends SQLiteOpenHelper2.{3. private static final String DBNAME = "itcast.db";4. private static final int VERSION = 1;5.6. public DBOpenHelper(Context context)7. {8. super(context, DBNAME, null, VERSION);9. }10.11.@Override12. public void onCreate(SQLiteDatabase db)13. {14. db.execSQL("CREATE TABLE IF NOT EXISTS filedownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER)");15. }16.@Override17. public void onUpgrade(SQLiteDatabase db, int oldVersion,int newVersion)18. {19. db.execSQL("DROP TABLE IF EXISTS filedownlog");20. onCreate(db);21. }22.}Java代码1./**2. * 文件下载业务bean3. */4.public class FileService5.{6. private DBOpenHelper openHelper;7. public FileService(Context context)8. {9. openHelper = new DBOpenHelper(context);10. }11. /**12. * 获取每条线程已经下载的文件长度13. * @param path14. * @return15. */16. public Map<Integer, Integer> getData(String path)17. {18. SQLiteDatabase db = openHelper.getReadableDatabase();19. Cursor cursor = db.rawQuery("select threadid, downlength from filedownlog where downpath=?", new String[]{path});20. Map<Integer, Integer> data = new HashMap<Integer, Integer>();21. while(cursor.moveToNext())22. {23. data.put(cursor.getInt(0), cursor.getInt(1));24. }25. cursor.close();26. db.close();27. return data;28. }29. /**30. * 保存每条线程已经下载的文件长度31. * @param path32. * @param map33. */34. public void save(String path, Map<Integer, Integer> map)35. {//int threadid, int position36. SQLiteDatabase db = openHelper.getWritableDatabase();37. db.beginTransaction();38. try39. {40. for(Map.Entry<Integer, Integer> entry : map.entrySet())41. {42. db.execSQL("insert into filedownlog(downpath,threadid, downlength) values(?,?,?)",43. new Object[]{path, entry.getKey(), entry.getValue()});44. }45. db.setTransactionSuccessful();46. }47. finally48. {49. db.endTransaction();50. }51. db.close();52. }53. /**54. * 实时更新每条线程已经下载的文件长度55. * @param path56. * @param map57. */58. public void update(String path, Map<Integer, Integer> map)59. {60. SQLiteDatabase db = openHelper.getWritableDatabase();61. db.beginTransaction();62. try{63. for(Map.Entry<Integer, Integer> entry : map.entrySet()){64. db.execSQL("update filedownlog set downlength=? where downpath=? and threadid=?",65. new Object[]{entry.getValue(), path,entry.getKey()});66. }67. db.setTransactionSuccessful();68. }finally{69. db.endTransaction();70. }71. db.close();72. }73. /**74. * 当文件下载完成后,删除对应的下载记录75. * @param path76. */77. public void delete(String path)78. {79. SQLiteDatabase db = openHelper.getWritableDatabase();80. db.execSQL("delete from filedownlog where downpath=?", new Object[]{path});81. db.close();82. }83.}。