在Http协议下实现多线程断点的下载

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.多线程下载的核心代码示例

  1. public class MulThreadDownload
  2. {
  3. /**
  4. * 多线程下载
  5. * @param args
  6. */
  7. public
    static void main(String[] args)
  8. {
  9. String path = "http://net.hoo.com/QQWubiSetup.exe";
  10. try
  11. {
  12. new MulThreadDownload().download(path,
    3);
  13. }
  14. catch (Exception e)
  15. {
  16. e.printStackTrace();
  17. }
  18. }
  19. /**
  20. * 从路径中获取文件名称
  21. * @param path 下载路径
  22. * @return
  23. */
  24. public static String getFilename(String path)
  25. {
  26. return path.substring(path.lastIndexOf(‘/‘)+1);
  27. }
  28. /**
  29. * 下载文件
  30. * @param path 下载路径
  31. * @param threadsize 线程数
  32. */
  33. public
    void download(String path, int threadsize)
    throws Exception
  34. {
  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. private
    final class DownloadThread
    extends Thread
  55. {
  56. private URL url;
  57. private File saveFile;
  58. private
    int block;//每条线程下载的数据长度
  59. private int threadid;//线程id
  60. public DownloadThread(URL url, File saveFile,
    int block, int threadid)
  61. {
  62. this.url = url;
  63. this.saveFile = saveFile;
  64. this.block = block;
  65. this.threadid = threadid;
  66. }
  67. @Override
  68. public
    void run()
  69. {
  70. //计算开始位置公式:线程id*每条线程下载的数据长度= ?
  71. //计算结束位置公式:(线程id +1)*每条线程下载的数据长度-1 =?
  72. int startposition = threadid * block;
  73. int endposition = (threadid +
    1 ) * block - 1;
  74. try
  75. {
  76. RandomAccessFile accessFile = new RandomAccessFile(saveFile,
    "rwd");
  77. //设置从什么位置开始写入数据
  78. accessFile.seek(startposition);
  79. HttpURLConnection conn = (HttpURLConnection)url.openConnection();
  80. conn.setRequestMethod("GET");
  81. conn.setConnectTimeout(5 *
    1000);
  82. conn.setRequestProperty("Range",
    "bytes="+ startposition+ "-"+ endposition);
  83. InputStream inStream = conn.getInputStream();
  84. byte[] buffer =
    new byte[1024];
  85. int len =
    0;
  86. while( (len=inStream.read(buffer)) != -1 )
  87. {
  88. accessFile.write(buffer, 0, len);
  89. }
  90. inStream.close();
  91. accessFile.close();
  92. System.out.println("线程id:"+ threadid+
    "下载完成");
  93. }
  94. catch (Exception e)
  95. {
  96. e.printStackTrace();
  97. }
  98. }
  99. }
  100. }

2.多线程断点下载功能,这里把断点数据保存到数据库中:注意代码注释的理解

(0)主Activity,关键点使用Handler更新进度条与开启线程下载避免ANR

若不使用Handler却要立即更新进度条数据,可使用:

//resultView.invalidate(); UI线程中立即更新进度条方法

//resultView.postInvalidate(); 非UI线程中立即更新进度条方法

  1. /**
  2. * 注意这里的设计思路,UI线程与参数保存问题,避免ANR问题,UI控件的显示
  3. * @author kay
  4. *
  5. */
  6. public class DownloadActivity
    extends Activity
  7. {
  8. private EditText downloadpathText;
  9. private TextView resultView;
  10. private ProgressBar progressBar;
  11. @Override
  12. public
    void onCreate(Bundle savedInstanceState)
  13. {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.main);
  16. downloadpathText = (EditText) this.findViewById(R.id.downloadpath);
  17. progressBar = (ProgressBar) this.findViewById(R.id.downloadbar);
  18. resultView = (TextView) this.findViewById(R.id.result);
  19. Button button = (Button) this.findViewById(R.id.button);
  20. button.setOnClickListener(new View.OnClickListener()
  21. {
  22. @Override
  23. public
    void onClick(View v)
  24. {
  25. //取得下载路径
  26. String path = downloadpathText.getText().toString();
  27. //判断SDCard是否存在
  28. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
  29. {
  30. //下载操作
  31. download(path, Environment.getExternalStorageDirectory());
  32. }
  33. else
  34. {
  35. Toast.makeText(DownloadActivity.this, R.string.sdcarderror,
    1).show();
  36. }
  37. }
  38. });
  39. }
  40. //主线程(UI线程)
  41. //业务逻辑正确,但是该程序运行的时候有问题(可能出现ANR问题)
  42. //对于显示控件的界面更新只是由UI线程负责,如果是在非UI线程更新控件的属性值,更新后的显示界面不会反映到屏幕上
  43. /**
  44. * 参数类型:因为启动一个线程还需要使用到上面方法的参数,而主方法启动后很快就会销毁,
  45. * 那么使用Final可以解决参数丢失的问题
  46. * path 注意是Final类型
  47. * savedir 注意是Final类型
  48. */
  49. private
    void download(final String path,
    final File savedir)
  50. {
  51. //这里开启一个线程避免ANR错误
  52. new Thread(new Runnable()
  53. {
  54. @Override
  55. public
    void run()
  56. {
  57. FileDownloader loader = new FileDownloader(DownloadActivity.this, path, savedir,
    3);
  58. //设置进度条的最大刻度为文件的长度
  59. progressBar.setMax(loader.getFileSize());
  60. try
  61. {
  62. loader.download(new DownloadProgressListener()
  63. {
  64. /**
  65. * 注意这里的设计,显示进度条数据需要使用Handler来处理
  66. * 因为非UI线程更新后的数据不能被刷新
  67. */
  68. @Override
  69. public
    void onDownloadSize(int size)
  70. {
  71. //实时获知文件已经下载的数据长度
  72. Message msg = new Message();
  73. //设置消息标签
  74. msg.what = 1;
  75. msg.getData().putInt("size", size);
  76. //使用Handler对象发送消息
  77. handler.sendMessage(msg);
  78. }
  79. });
  80. }
  81. catch (Exception e)
  82. {
  83. //发送一个空消息到消息队列
  84. handler.obtainMessage(-1).sendToTarget();
  85. /**
  86. *  或者使用下面的方法发送一个空消息
  87. *  Message msg = new Message();
  88. *  msg.what = 1;
  89. *  handler.sendMessage(msg);
  90. */
  91. }
  92. }
  93. }).start();
  94. }
  95. /**Handler原理:当Handler被创建时会关联到创建它的当前线程的消息队列,该类用于往消息队列发送消息
  96. *
  97. * 消息队列中的消息由当前线程内部进行处理
  98. */
  99. private Handler handler =
    new Handler()
  100. {
  101. //重写Handler里面的handleMessage方法处理消息
  102. @Override
  103. public
    void handleMessage(Message msg)
  104. {
  105. switch (msg.what)
  106. {
  107. case
    1:
  108. //进度条显示
  109. progressBar.setProgress(msg.getData().getInt("size"));
  110. float num = (float)progressBar.getProgress()/(float)progressBar.getMax();
  111. int result = (int)(num*100);
  112. //resultView.invalidate(); UI线程中立即更新进度条方法
  113. //resultView.postInvalidate(); 非UI线程中立即更新进度条方法
  114. resultView.setText(result+ "%");
  115. //判断是否下载成功
  116. if(progressBar.getProgress()==progressBar.getMax())
  117. {
  118. Toast.makeText(DownloadActivity.this, R.string.success,
    1).show();
  119. }
  120. break;
  121. case -1:
  122. Toast.makeText(DownloadActivity.this, R.string.error,
    1).show();
  123. break;
  124. }
  125. }
  126. };
  127. }

(1)下载类:

注意计算每条线程的下载长度与下载起始位置的方法

  1. public class DownloadThread
    extends Thread
  2. {
  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. @Override
  23. public void run()
  24. {
  25. //未下载完成
  26. if(downLength < block)
  27. {
  28. try
  29. {
  30. HttpURLConnection http = (HttpURLConnection) downUrl.openConnection();
  31. http.setConnectTimeout(5 *
    1000);
  32. http.setRequestMethod("GET");
  33. 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, */*");
  34. http.setRequestProperty("Accept-Language",
    "zh-CN");
  35. http.setRequestProperty("Referer", downUrl.toString());
  36. http.setRequestProperty("Charset",
    "UTF-8");
  37. //下载开始位置:线程id*每条线程下载的数据长度 = ?
  38. int startPos = block * (threadId -
    1) + downLength;
  39. //下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
  40. int endPos = block * threadId -1;
  41. //设置获取实体数据的范围
  42. http.setRequestProperty("Range",
    "bytes=" + startPos + "-"+ endPos);
  43. 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)");
  44. http.setRequestProperty("Connection",
    "Keep-Alive");
  45. InputStream inStream = http.getInputStream();
  46. byte[] buffer =
    new byte[1024];
  47. int offset =
    0;
  48. print("Thread " +
    this.threadId + " start download from position "+ startPos);
  49. RandomAccessFile threadfile = new RandomAccessFile(this.saveFile,
    "rwd");
  50. threadfile.seek(startPos);
  51. while ((offset = inStream.read(buffer,
    0, 1024)) != -1)
  52. {
  53. threadfile.write(buffer, 0, offset);
  54. downLength += offset;
  55. downloader.update(this.threadId, downLength);
  56. downloader.append(offset);
  57. }
  58. threadfile.close();
  59. inStream.close();
  60. print("Thread " +
    this.threadId + " download finish");
  61. //标记是否完成
  62. this.finish =
    true;
  63. }
  64. catch (Exception e)
  65. {
  66. this.downLength = -1;
  67. print("Thread "+
    this.threadId+ ":"+ e);
  68. }
  69. }
  70. }
  71. private static
    void print(String msg)
  72. {
  73. Log.i(TAG, msg);
  74. }
  75. /**
  76. * 下载是否完成
  77. * @return
  78. */
  79. public
    boolean isFinish()
  80. {
  81. return finish;
  82. }
  83. /**
  84. * 已经下载的内容大小
  85. * @return 如果返回值为-1,代表下载失败
  86. */
  87. public long getDownLength()
  88. {
  89. return downLength;
  90. }

文件下载器,使用

  1. /**
  2. * 文件下载器,使用这个类的方法如下示例:
  3. * FileDownloader loader = new FileDownloader(context, "http://browse.babasport.com/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 FileDownloader
  19. {
  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. * @return
  45. */
  46. public int getFileSize()
  47. {
  48. return fileSize;
  49. }
  50. /**
  51. * 累计已下载大小
  52. * @param size
  53. */
  54. protected synchronized
    void append(int size)
  55. {
  56. downloadSize += size;
  57. }
  58. /**
  59. * 更新指定线程最后下载的位置
  60. * @param threadId 线程id
  61. * @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. try
  77. {
  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-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, */*");
  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 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)");
  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, filename);
  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.getValue());
  112. }
  113. //下面计算所有线程已经下载的数据长度
  114. if(this.data.size()==this.threads.length)
  115. {
  116. for (int i =
    0; i < this.threads.length; 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.fileSize / this.threads.length +
    1;
  124. }
  125. else
  126. {
  127. throw
    new RuntimeException("server no response ");
  128. }
  129. }
  130. catch (Exception e)
  131. {
  132. print(e.toString());
  133. throw
    new RuntimeException("don‘t connection this url");
  134. }
  135. }
  136. /**
  137. * 获取文件名
  138. */
  139. private String getFileName(HttpURLConnection conn)
  140. {
  141. String filename = this.downloadUrl.substring(this.downloadUrl.lastIndexOf(‘/‘) +
    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.getHeaderFieldKey(i).toLowerCase())){
  147. Matcher m = Pattern.compile(".*filename=(.*)").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. * @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null
  158. * @return 已下载文件大小
  159. * @throws Exception
  160. */
  161. public int download(DownloadProgressListener listener)
    throws Exception{
  162. try
  163. {
  164. //创建本地文件
  165. RandomAccessFile randOut = new RandomAccessFile(this.saveFile,
    "rw");
  166. if(this.fileSize>0) randOut.setLength(this.fileSize);
  167. randOut.close();
  168. URL url = new URL(this.downloadUrl);
  169. if(this.data.size() !=
    this.threads.length)
  170. {
  171. this.data.clear();
  172. for (int i =
    0; i < this.threads.length; i++)
  173. {
  174. //初始化每条线程已经下载的数据长度为0
  175. this.data.put(i+1,
    0);
  176. }
  177. }
  178. //开启线程进行下载
  179. for (int i =
    0; i < this.threads.length; i++)
  180. {
  181. int downLength =
    this.data.get(i+1);
  182. //判断线程是否已经完成下载,否则继续下载
  183. if(downLength <
    this.block && this.downloadSize<this.fileSize)
  184. {
  185. this.threads[i] =
    new DownloadThread(this, url,
    this.saveFile, this.block,
    this.data.get(i+1), i+1);
  186. this.threads[i].setPriority(7);//可删除这条
  187. this.threads[i].start();
  188. }
  189. else
  190. {
  191. this.threads[i] =
    null;
  192. }
  193. }
  194. this.fileService.save(this.downloadUrl,
    this.data);
  195. //下载未完成
  196. boolean notFinish =
    true;
  197. // 循环判断所有线程是否完成下载
  198. while (notFinish)
  199. {
  200. Thread.sleep(900);
  201. //假定全部线程下载完成
  202. notFinish = false;
  203. for (int i =
    0; i < this.threads.length; i++)
  204. {
  205. //如果发现线程未完成下载
  206. if (this.threads[i] !=
    null && !this.threads[i].isFinish())
  207. {
  208. //设置标志为下载没有完成
  209. notFinish = true;
  210. //如果下载失败,再重新下载
  211. if(this.threads[i].getDownLength() == -1)
  212. {
  213. this.threads[i] =
    new DownloadThread(this, url,
    this.saveFile, this.block,
    this.data.get(i+1), i+1);
  214. this.threads[i].setPriority(7);
  215. this.threads[i].start();
  216. }
  217. }
  218. }
  219. //通知目前已经下载完成的数据长度
  220. if(listener!=null) listener.onDownloadSize(this.downloadSize);
  221. }
  222. //删除数据库中下载信息
  223. fileService.delete(this.downloadUrl);
  224. }
  225. catch (Exception e)
  226. {
  227. print(e.toString());
  228. throw
    new Exception("file download fail");
  229. }
  230. return
    this.downloadSize;
  231. }
  232. /**
  233. * 获取Http响应头字段
  234. * @param http
  235. * @return
  236. */
  237. public
    static Map<String, String> getHttpResponseHeader(HttpURLConnection http) {
  238. Map<String, String> header = new LinkedHashMap<String, String>();
  239. for (int i =
    0;; i++) {
  240. String mine = http.getHeaderField(i);
  241. if (mine ==
    null) break;
  242. header.put(http.getHeaderFieldKey(i), mine);
  243. }
  244. return header;
  245. }
  246. /**
  247. * 打印Http头字段
  248. * @param http
  249. */
  250. public static
    void printResponseHeader(HttpURLConnection http)
  251. {
  252. Map<String, String> header = getHttpResponseHeader(http);
  253. for(Map.Entry<String, String> entry : header.entrySet())
  254. {
  255. String key = entry.getKey()!=null ? entry.getKey()+
    ":" : "";
  256. print(key+ entry.getValue());
  257. }
  258. }
  1. public interface DownloadProgressListener
  2. {
  3. public
    void onDownloadSize(int size);
  4. }

(2)文件操作,断点数据库存储

  1. public class DBOpenHelper
    extends SQLiteOpenHelper
  2. {
  3. private
    static final String DBNAME =
    "itcast.db";
  4. private static
    final int VERSION =
    1;
  5. public DBOpenHelper(Context context)
  6. {
  7. super(context, DBNAME,
    null, VERSION);
  8. }
  9. @Override
  10. public void onCreate(SQLiteDatabase db)
  11. {
  12. db.execSQL("CREATE TABLE IF NOT EXISTS filedownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER)");
  13. }
  14. @Override
  15. public
    void onUpgrade(SQLiteDatabase db, int oldVersion,
    int newVersion)
  16. {
  17. db.execSQL("DROP TABLE IF EXISTS filedownlog");
  18. onCreate(db);
  19. }
  20. }
  1. **
  2. * 文件下载业务bean
  3. */
  4. public class FileService
  5. {
  6. private DBOpenHelper openHelper;
  7. public FileService(Context context)
  8. {
  9. openHelper = new DBOpenHelper(context);
  10. }
  11. /**
  12. * 获取每条线程已经下载的文件长度
  13. * @param path
  14. * @return
  15. */
  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 path
  32. * @param map
  33. */
  34. public void save(String path,  Map<Integer, Integer> map)
  35. {//int threadid, int position
  36. SQLiteDatabase db = openHelper.getWritableDatabase();
  37. db.beginTransaction();
  38. try
  39. {
  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. finally
  48. {
  49. db.endTransaction();
  50. }
  51. db.close();
  52. }
  53. /**
  54. * 实时更新每条线程已经下载的文件长度
  55. * @param path
  56. * @param map
  57. */
  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 path
  76. */
  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. }
时间: 2024-10-14 05:46:32

在Http协议下实现多线程断点的下载的相关文章

C#实现http协议下的多线程文件传输

用C#实现HTTP协议下的多线程文件传输转自  http://developer.51cto.com/art/201105/263066_all.htm C#(C Sharp)是微软(Microsoft)为.NET Framework量身订做的程序语言,C#拥有C/C++的强大功能以及Visual Basic简易使用的特性,是第一个组件导向(Component-oriented)的程序语言,和C++与Java一样亦为对象导向(object-oriented)程序语言.下面主要介绍的是用C#实现H

JAVA下实现多线程断点下载

多线程断点下载:顾名思义是用多线程实现的,断点是当第三方因素(断电.断网等)中断下载时,下次下载可以继续上次下载的地方下载. 1.通过getContentLength可以获取要下载文件的大小,这样可以在本机上创建一个相同大小的文件用来下载. int fileLength = connection.getContentLength(); 2.由于是多线程,所以要给每一个线程均分分配要下载的位置. for(int i = 0; i < threadCount; i ++) { int startTh

安卓系统下的多线程断点下载实现

近期研究多线程下载,写了个demo.整理下来,或许会对别人有帮助. 多线程下载的话一般开启两到三个线程吧.假设线程太多的话时间会浪费在线程的切换上,倒是浪费了大把的时间.线程多了也不是一件好事. 原理的话看我的还有一篇博文,其实是将代码移植到了安卓系统上.java实现的多线程下载demo public class MainActivity extends Activity { protected static final int DOWNLOAD_ERROR = 1; private stati

安卓系统下的多线程断点下载实现2利用开源框架XUtils

使用开源框架可以大大降低开发的难度,减少开发的周期,并且bug也少的多,软件运行起来更稳定. xUtils简介 xUtils 包含了很多实用的android工具. xUtils 支持大文件上传,更全面的http请求协议支持(10种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响- xUitls 最低兼容android 2.2 (api level 8) 下载地址:https://github.com/wyouflf/xUtils 下面是一个demo: public class Ma

多线程断点下载原理(java代码实例演示)

其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载,首先:你必须明白第一点,那么就是,什么是多线程下载,该知识点可以查看本博客上一篇文章,Android之多线程下载原理,断点下载呢,其实就是在这个的基础之上添加了一些东西,那么添加了什么东西了,现在来做一个详细的了解. 1.在下载的过程中,边下载,变用一个文件来记录下载的位置,也就是下载了多少的数据 1.创建文件 2.记录下载多少数据 3.存储数据 2.第二次下载的时候,就去读取文件中是否存有数据,读取上次下载的位置

Android/java http多线程断点下载(附源码)

先看下项目结构: http多线程断点下载涉及到 数据库,多线程和http请求等几个模块,东西不是很多,想弄清楚也不是很困难,接下来我和大家分享下我的做法. 一.先看MainActivity.java 成员变量,主要是一些下载过程的变量和handler private String path = "http://192.168.1.3:8080/wanmei/yama.apk"; private String sdcardPath; private int threadNum = 5;

iOS开发网络篇—大文件的多线程断点下载(转)

http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分). 项目中用到的主要

iOS开发网络篇—多线程断点下载

iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分). 项目中用到的主要类如下: 完成的实现代码如下: 主控制器中的代码: 1 #import "YYViewControl

iOS开发网络请求——大文件的多线程断点下载

iOS开发中网络请求技术已经是移动app必备技术,而网络中文件传输就是其中重点了.网络文件传输对移动客户端而言主要分为文件的上传和下载.作为开发者从技术角度会将文件分为小文件和大文件.小文件因为文件大小比较小导致传输所需时间少传输就快,因此不太容易影响用户体验,可用的技术就多.而大文件因为文件大小比较大导致传输时间长,因此就需要考虑到各种用户体验,比如避免在上传下载文件过程中阻塞主线程影响用户体验,就需要使用到多线程技术:为了给用户友好的进度提示,因此又需要开发中跟踪数据上传和下载数据的变化:为