多线程下载

楼主三年磨剑(当然不是磨着一把剑),倾血奉献Android多线程下载Demo。有的人就问了“怎么写来写去还是Demo?”,因为老哥我实在太忙了,
每天写一点,写到现在也才写了个下载器,也就差下载管理类就是个完整的模块了。对于新手学习这已经足够了,不对,是完全足够了。

这不仅仅只是一个简单的Demo,这绝对是你前所未见的商业级别的范例,集支持多线程下载,断点续传,只使用wifi网络下载,显示下载速度,人性化提示
及超强的容错机制多功能于一体,绝对的实用,绝对的专业。

当然我写这个是为了下载apk的,大家稍微改一改就可以写成更通用的下载器。唯一有点不足的地方就是在Android上使用RandomAccessFile在创建大文件的时候
速度有些慢,导致前几秒的进度都为0。不知道有没有人可以帮我解决这个问题。

下面给出关键代码。

[java] view
plain
copy

  1. package com.h3c.DownloadEngine;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.RandomAccessFile;  
  7. import java.net.HttpURLConnection;  
  8. import java.net.URL;  
  9. import java.util.ArrayList;  
  10.   
  11. import android.content.Context;  
  12. import android.os.Environment;  
  13. import android.util.Log;  
  14.   
  15. import com.h3c.DownloadEngine.common.DownloaderErrorException;  
  16. import com.h3c.DownloadEngine.common.EngineConstants;  
  17. import com.h3c.DownloadEngine.common.EngineUtil;  
  18. import com.h3c.DownloadEngine.common.EngineVariable;  
  19. import com.h3c.DownloadEngine.db.EngineDBOperator;  
  20. import com.h3c.DownloadEngine.entity.DownloadBean;  
  21.   
  22. public class Downloader {  
  23.     private final static String TAG = "Downloader";  
  24.     private final static byte[] lock_getFileSize = new byte[1];  
  25.     private final static byte[] lock_refresh_progress = new byte[1];  
  26.   
  27.     private int mThreadCount = 4;// 默认子线程数为4个  
  28.     private int bufferSize = 1024 * 16; // 16K 一个块  
  29.   
  30.     private DownloadBean mBean;// 注意,这里是dwonloader的bean不是其subBean  
  31.     private Context mContext;  
  32.     private DownloadEngineCallback mCallback;  
  33.     private EngineDBOperator mDBOper;  
  34.     private int mDoneThreadCount = 0;// 完成的线程数  
  35.     private int mState = EngineConstants.DOWNLOAD_STATE_INIT;// 下载器状态  
  36.     private ArrayList<DownloadBean> mBeans = new ArrayList<DownloadBean>(  
  37.             mThreadCount);  
  38.   
  39.     public Downloader(DownloadBean bean, Context context,  
  40.             DownloadEngineCallback callback) throws DownloaderErrorException {  
  41.         this.mBean = bean;  
  42.         this.mContext = context;  
  43.         this.mCallback = callback;  
  44.         this.mDBOper = EngineDBOperator.getInstance(context);  
  45.   
  46.         if (this.mDBOper != null) {  
  47.             if (this.mDBOper.isHasDownloadTaskByUrl(bean.url)) {// 如果此任务已经存放进数据库  
  48.                 getDownloaderInfoFromDB(bean);  
  49.             } else {// 插入信息至数据库  
  50.                 addDownloaderInfoToDB(bean);  
  51.             }  
  52.         } else {  
  53.             callBackError("Downloader错误,可能是EngineDBOperator为Null.");  
  54.             throw new DownloaderErrorException(  
  55.                     "Downloader错误,可能是EngineDBOperator为Null.");  
  56.         }  
  57.     }  
  58.   
  59.     public DownloadBean getDownloaderInfo() {  
  60.         return mBean;  
  61.     }  
  62.   
  63.     public int getDownloaderState() {  
  64.         return mState;  
  65.     }  
  66.   
  67.     /** 
  68.      * 请求初始化 
  69.      *  
  70.      * @param state 
  71.      */  
  72.     protected void setDownloaderState(int state) {  
  73.         mState = state;  
  74.         if (state == EngineConstants.DOWNLOAD_STATE_INIT) {  
  75.             mBean.currentPosition = 0;  
  76.         }  
  77.     }  
  78.   
  79.     /** 
  80.      * 加入下载信息进入数据库,此方法用于刚刚初始化Downloader,且数据库中没有该任务的时候 
  81.      *  
  82.      * @param bean 
  83.      * @throws DownloaderErrorException 
  84.      */  
  85.     private void addDownloaderInfoToDB(DownloadBean bean)  
  86.             throws DownloaderErrorException {  
  87.         if (mState != EngineConstants.DOWNLOAD_STATE_INIT  
  88.                 && mState != EngineConstants.DOWNLOAD_STATE_STOP  
  89.                 && mState != EngineConstants.DOWNLOAD_STATE_ERROR) {  
  90.             callBackError("这个任务已经加入到数据库中了");  
  91.             throw new DownloaderErrorException("这个任务已经加入到数据库中了");  
  92.         }  
  93.   
  94.         if (mDBOper != null) {  
  95.             long fileSize = bean.fileSize;  
  96.             if (mBeans.size() > 0) {  
  97.                 mBeans.clear();  
  98.             }  
  99.   
  100.             try {  
  101.                 if (fileSize > 0) {// 判断传入的fileSize大小,如果大于0,就不用从网络中获取,直接初始化N个子下载器  
  102.                     if (!hasSpaceInSDCard()) {  
  103.                         return;  
  104.                     }  
  105.                     long range = fileSize / mThreadCount;// 文件分段值  
  106.                     for (int i = 0; i < mThreadCount - 1; i++) {  
  107.                         DownloadBean subBean = (DownloadBean) bean.clone();  
  108.                         subBean.threadId = i;  
  109.                         subBean.startPosition = i * range;  
  110.                         subBean.endPosition = (i + 1) * range - 1;  
  111.                         mBeans.add(subBean);  
  112.                     }  
  113.   
  114.                     DownloadBean subBean = (DownloadBean) bean.clone();  
  115.                     subBean.threadId = mThreadCount - 1;  
  116.                     subBean.startPosition = (mThreadCount - 1) * range;  
  117.                     subBean.endPosition = fileSize - 1;  
  118.                     mBeans.add(subBean);  
  119.                 } else {// 如果等于0,就直接初始化N个0大小的子下载器  
  120.                     for (int n = 0; n < mThreadCount - 1; n++) {  
  121.                         DownloadBean subBean = (DownloadBean) bean.clone();  
  122.                         subBean.threadId = n;  
  123.                         mBeans.add(subBean);  
  124.                     }  
  125.   
  126.                     DownloadBean subBean = (DownloadBean) bean.clone();  
  127.                     subBean.threadId = mThreadCount - 1;  
  128.                     mBeans.add(subBean);  
  129.                 }  
  130.   
  131.                 mDBOper.addDownloadTask(mBeans);  
  132.                 if (bean.fileSize > 0) {// 如果文件大小已经获取就进入等待状态  
  133.                     mState = EngineConstants.DOWNLOAD_STATE_WAITTING;// 下载器进入等待状态  
  134.                 } else {// 文件大小未获取就开启线程去获取文件大小并更新子下载器中的内容  
  135.                     new Thread(new Runnable() {  
  136.                         @Override  
  137.                         public void run() {  
  138.                             boolean flag = false;  
  139.                             synchronized (lock_getFileSize) {  
  140.                                 flag = getFileSizeByNetwork(mBean);  
  141.                             }  
  142.                             if (flag) {  
  143.                                 mState = EngineConstants.DOWNLOAD_STATE_WAITTING;// 下载器进入等待状态  
  144.                             } else {  
  145.                                 Log.e(TAG, "从网络中获取文件大小失败 1");  
  146.                             }  
  147.                         }  
  148.                     }).start();  
  149.   
  150.                 }  
  151.             } catch (CloneNotSupportedException e) {  
  152.                 e.printStackTrace();  
  153.             }  
  154.         } else {  
  155.             callBackError("addDownloaderInfoToDB错误,可能是EngineDBOperator为Null.");  
  156.             throw new DownloaderErrorException(  
  157.                     "addDownloaderInfoToDB错误,可能是EngineDBOperator为Null.");  
  158.         }  
  159.     }  
  160.   
  161.     /** 
  162.      * 从数据库中读取下载器信息 
  163.      *  
  164.      * @param bean 
  165.      * @throws DownloaderErrorException 
  166.      */  
  167.     private void getDownloaderInfoFromDB(DownloadBean bean)  
  168.             throws DownloaderErrorException {  
  169.         if (mDBOper != null) {  
  170.             mBeans.clear();  
  171.             mBeans = mDBOper.getDownloadTaskByUrl(bean.url);  
  172.   
  173.             mBean.currentPosition = 0;  
  174.             mBean.fileSize = 0;  
  175.             mThreadCount = mBeans.size();  
  176.             for (DownloadBean subBean : mBeans) {  
  177.                 mBean.currentPosition += subBean.currentPosition;  
  178.                 if (subBean.fileSize > mBean.fileSize) {  
  179.                     mBean.fileSize = subBean.fileSize;  
  180.                 }  
  181.             }  
  182.   
  183.             if (mBean.fileSize < 1) {  
  184.                 new Thread(new Runnable() {  
  185.                     @Override  
  186.                     public void run() {  
  187.                         boolean flag = false;  
  188.                         synchronized (lock_getFileSize) {  
  189.                             flag = getFileSizeByNetwork(mBean);  
  190.                         }  
  191.                         if (flag) {  
  192.                             mState = EngineConstants.DOWNLOAD_STATE_WAITTING;// 下载器进入等待状态  
  193.                         } else {  
  194.                             Log.e(TAG, "从网络中获取文件大小失败 2");  
  195.                         }  
  196.                     }  
  197.                 }).start();  
  198.             } else {  
  199.                 mState = EngineConstants.DOWNLOAD_STATE_WAITTING;// 下载器进入等待状态  
  200.             }  
  201.         } else {  
  202.             callBackError("getDownloaderInfoFromDB Error,May be EngineDBOperator is Null.");  
  203.             throw new DownloaderErrorException(  
  204.                     "getDownloaderInfoFromDB Error,May be EngineDBOperator is Null.");  
  205.         }  
  206.     }  
  207.   
  208.     /** 
  209.      * 从网络中获取文件大小,并更新listBeans 
  210.      */  
  211.     private boolean getFileSizeByNetwork(DownloadBean bean) {  
  212.         HttpURLConnection connection = null;  
  213.         long fileSize = bean.fileSize;  
  214.         try {  
  215.             if (fileSize <= 0) {// 如果没有传入文件大小就从网络中获取  
  216.                 URL url = new URL(bean.url);  
  217.                 connection = (HttpURLConnection) url.openConnection();  
  218.                 connection.setConnectTimeout(5000);  
  219.                 connection.setReadTimeout(8000);  
  220.   
  221.                 if (android.os.Build.VERSION.SDK_INT > 10) {// 规避2.x上因为加入setRM导致连接超时的bug  
  222.                     connection.setRequestMethod("HEAD");// head  
  223.                 }  
  224.   
  225.                 int resopnseCode = connection.getResponseCode();  
  226.                 if (resopnseCode != 200 && resopnseCode != 206) {  
  227.                     callBackError("http返回码不正确:" + resopnseCode);  
  228.                     return false;  
  229.                 }  
  230.                 // 获得文件大小  
  231.                 fileSize = connection.getContentLength();  
  232.                 mBean.fileSize = fileSize;  
  233.   
  234.                 if (fileSize <= 0) {  
  235.                     callBackError("无法从服务器上获得文件大小" + fileSize);  
  236.                     return false;  
  237.                 }  
  238.   
  239.                 // if (connection.getHeaderField("Content-Range") == null) {  
  240.                 // Log.e(TAG, "服务器不支持断点续传");  
  241.                 // mThreadCount = 1;  
  242.                 // }  
  243.   
  244.                 // 如果没有存储空间了  
  245.                 if (!hasSpaceInSDCard()) {  
  246.                     return false;  
  247.                 }  
  248.   
  249.                 long range = fileSize / mThreadCount;// 文件分段值  
  250.                 // 更新listBean  
  251.                 for (int i = 0; i < mThreadCount - 1; i++) {  
  252.                     DownloadBean subBean = mBeans.get(i);  
  253.                     subBean.fileSize = fileSize;  
  254.                     subBean.startPosition = i * range;  
  255.                     subBean.endPosition = (i + 1) * range - 1;  
  256.                 }  
  257.   
  258.                 DownloadBean subBean = mBeans.get(mThreadCount - 1);  
  259.                 subBean.fileSize = fileSize;  
  260.                 subBean.startPosition = (mThreadCount - 1) * range;  
  261.                 subBean.endPosition = fileSize - 1;  
  262.   
  263.                 // 更新数据库  
  264.                 if (mDBOper != null) {  
  265.                     mDBOper.updateTaskCompleteSize(mBeans, mBean.url);  
  266.                 } else {  
  267.                     callBackError("getFileSizeByNetwork错误,可能是EngineDBOperator is Null.");  
  268.                     throw new DownloaderErrorException(  
  269.                             "getFileSizeByNetwork错误,可能是EngineDBOperator is Null.");  
  270.                 }  
  271.                 return true;  
  272.             } else {// 文件有大小就直接退出  
  273.                 return true;  
  274.             }  
  275.         } catch (Exception e) {  
  276.             callBackError("从服务器获取文件大小超时");  
  277.             e.printStackTrace();  
  278.         } finally {  
  279.             if (connection != null) {  
  280.                 connection.disconnect();  
  281.             }  
  282.         }  
  283.         return false;  
  284.     }  
  285.   
  286.     /** 
  287.      * 开始下载,可能多次调用 
  288.      */  
  289.     public void startDownloader() {  
  290.         if (mState == EngineConstants.DOWNLOAD_STATE_DOWNLOADING) {// 如果正在下载就return  
  291.             return;  
  292.         }  
  293.   
  294.         if (mBean == null) {  
  295.             callBackError("下载器没有初始化");  
  296.             return;  
  297.         }  
  298.   
  299.         File file = new File(mBean.savePath);  
  300.         File parentDirectory = file.getParentFile();  
  301.         if (!parentDirectory.exists()) {  
  302.             parentDirectory.mkdirs();  
  303.         }  
  304.   
  305.         if (!file.exists()) {  
  306.             try {  
  307.                 file.createNewFile();  
  308.             } catch (IOException e) {  
  309.                 e.printStackTrace();  
  310.             }  
  311.         }  
  312.           
  313.         if (mBeans.size() < 1) {// 防止由于发生错误导致清空了mBeans列表,但是又重新开始了任务,所有要再次初始化mBeans  
  314.             try {  
  315.                 addDownloaderInfoToDB(mBean);  
  316.             } catch (DownloaderErrorException e) {  
  317.                 e.printStackTrace();  
  318.                 return;  
  319.             }  
  320.         }  
  321.   
  322.         /** 
  323.          * 只有获得文件大小后才会开始下载 
  324.          */  
  325.         synchronized (lock_getFileSize) {  
  326.             if (mState == EngineConstants.DOWNLOAD_STATE_INIT) {// 获取文件大小失败,重新获取  
  327.                 boolean flag = getFileSizeByNetwork(mBean);  
  328.                 if (!flag) {  
  329.                     callBackError("获取文件大小失败");  
  330.                     return;  
  331.                 }  
  332.             }  
  333.         }  
  334.   
  335.         mState = EngineConstants.DOWNLOAD_STATE_DOWNLOADING;  
  336.         mDBOper.removePauseFileByUrl(mBean.url);// 从暂停列表中移除  
  337.         mDoneThreadCount = 0;// 初始化完成线程数  
  338.   
  339.         for (DownloadBean bean : mBeans) {  
  340.             if (bean.currentPosition < (bean.endPosition - bean.startPosition)) {// 如果该线程属于没有下载完成的  
  341.                 HamalThread hamalThread = new HamalThread(bean);  
  342.                 hamalThread.start();  
  343.             } else {// 已经完成的线程不需要重新创建  
  344.                 mDoneThreadCount++;  
  345.             }  
  346.         }  
  347.           
  348.         if (mDoneThreadCount == mThreadCount) {// 下载完成  
  349.             downloaderDone();  
  350.         }  
  351.     }  
  352.   
  353.     private class HamalThread extends Thread {  
  354.         private int threadId;  
  355.         private long startPos;  
  356.         private long endPos;  
  357.         private long compeleteSize;  
  358.         private String urlstr;  
  359.   
  360.         public HamalThread(DownloadBean bean) {  
  361.             this.threadId = bean.threadId;  
  362.             this.startPos = bean.startPosition;  
  363.             this.endPos = bean.endPosition;  
  364.             this.compeleteSize = bean.currentPosition;  
  365.             this.urlstr = bean.url;  
  366.         }  
  367.   
  368.         @Override  
  369.         public void run() {  
  370.             HttpURLConnection connection = null;  
  371.             RandomAccessFile randomAccessFile = null;  
  372.             InputStream is = null;  
  373.             try {  
  374.                 URL url = new URL(urlstr);  
  375.                 connection = (HttpURLConnection) url.openConnection();  
  376.                 connection.setConnectTimeout(5000);  
  377.                 connection.setReadTimeout(8000);  
  378.                 connection.setRequestMethod("GET");  
  379.                 if (mThreadCount > 1) {// 多线程下载  
  380.                     // 设置范围,格式为Range:bytes x-y;  
  381.                     connection.setRequestProperty("Range", "bytes="  
  382.                             + (startPos + compeleteSize) + "-" + endPos);  
  383.                 }  
  384.   
  385.                 randomAccessFile = new RandomAccessFile(mBean.savePath, "rwd");  
  386.                 randomAccessFile.seek(startPos + compeleteSize);  
  387.                 // 将要下载的文件写到保存在保存路径下的文件中  
  388.                 is = connection.getInputStream();  
  389.                 byte[] buffer = new byte[bufferSize];  
  390.                 int length = -1;  
  391.                 EngineUtil eUtil = EngineUtil.getInstance();  
  392.   
  393.                 if (EngineVariable.SUPPORT_NETWORK_TYPE == EngineConstants.DOWNLOAD_NETWORK_ONLYWIFI) {// 如果只能是3G下载  
  394.                     if (eUtil.getNetworkType() != EngineConstants.NETWORK_STATE_WIFI) {// 且当前网络不是Wifi  
  395.                         interruptDownloader();  
  396.                         return;  
  397.                     }  
  398.                 }  
  399.   
  400.                 while ((length = is.read(buffer)) != -1) {  
  401.                     // 网络判断  
  402.                     if (EngineVariable.SUPPORT_NETWORK_TYPE == EngineConstants.DOWNLOAD_NETWORK_ONLYWIFI) {// 如果只能是3G下载  
  403.                         if (eUtil.getNetworkType() != EngineConstants.NETWORK_STATE_WIFI) {// 且当前网络不是Wifi  
  404.                             interruptDownloader();  
  405.                             return;  
  406.                         }  
  407.                     }  
  408.   
  409.                     randomAccessFile.write(buffer, 0, length);  
  410.                     compeleteSize += length;  
  411.                     synchronized (lock_refresh_progress) {  
  412.                         mBean.currentPosition += length;  
  413.                     }  
  414.                     // 更新数据库中的下载信息  
  415.                     mDBOper.updateTaskCompleteSize(threadId, compeleteSize,  
  416.                             urlstr);  
  417.                     if (mState == EngineConstants.DOWNLOAD_STATE_PAUSE  
  418.                             || mState == EngineConstants.DOWNLOAD_STATE_INTERRUPT  
  419.                             || mState == EngineConstants.DOWNLOAD_STATE_STOP  
  420.                             || mState == EngineConstants.DOWNLOAD_STATE_ERROR) {// 暂停  
  421.                         return;  
  422.                     }  
  423.                 }  
  424.   
  425.                 // 该子线程下载完成  
  426.                 mDoneThreadCount++;  
  427.             } catch (Exception e) {  
  428.                 Log.e(TAG, "下载途中断掉了连接...");  
  429.                 interruptDownloader();  
  430.                 e.printStackTrace();  
  431.             } finally {  
  432.                 try {  
  433.                     is.close();  
  434.                     randomAccessFile.close();  
  435.                     connection.disconnect();  
  436.                 } catch (Exception e) {  
  437.                     e.printStackTrace();  
  438.                 }  
  439.             }  
  440.   
  441.             if (mDoneThreadCount == mThreadCount) {  
  442.                 downloaderDone();  
  443.             }  
  444.         }  
  445.     }  
  446.   
  447.     /** 
  448.      * 获取下载进度 
  449.      *  
  450.      * @return 
  451.      */  
  452.     public int getProgress() {  
  453.         if (mBean.fileSize < 1) {  
  454.             return 0;  
  455.         }  
  456.         return (int) (mBean.currentPosition * 100 / mBean.fileSize);  
  457.     }  
  458.   
  459.     /** 
  460.      * 暂停下载 
  461.      */  
  462.     public void pauseDownloader() {  
  463.         mState = EngineConstants.DOWNLOAD_STATE_PAUSE;  
  464.         mDBOper.addPauseFile(mBean.url, mBean.packageName, mBean.fileId);  
  465.     }  
  466.   
  467.     /** 
  468.      * 中断下载(非人为的暂停) 
  469.      */  
  470.     private void interruptDownloader() {  
  471.         mState = EngineConstants.DOWNLOAD_STATE_INTERRUPT;  
  472.     }  
  473.   
  474.     /** 
  475.      * 结束下载 
  476.      */  
  477.     public void stopDownloader() {  
  478.         mState = EngineConstants.DOWNLOAD_STATE_STOP;  
  479.         mBean.currentPosition = 0;  
  480.         removeDownloaderInfo(mBean.url);  
  481.     }  
  482.   
  483.     /** 
  484.      * 清除下载的信息 
  485.      *  
  486.      * @param urlstr 
  487.      */  
  488.     private void removeDownloaderInfo(String urlstr) {  
  489.         mDBOper.deleteDownloadTaskByUrl(urlstr);  
  490.         mDBOper.removePauseFileByUrl(urlstr);  
  491.         mBeans.clear();  
  492.     }  
  493.   
  494.     /** 
  495.      * 下载完成 
  496.      */  
  497.     private void downloaderDone() {  
  498.         mState = EngineConstants.DOWNLOAD_STATE_DONE;  
  499.         mBean.doneTime = System.currentTimeMillis();  
  500.         mCallback.callbackWhenDownloadTaskListener(mState, mBean,  
  501.                 mBean.fileName + "下载完成");  
  502.   
  503.         removeDownloaderInfo(mBean.url);  
  504.         mDBOper.addCompleteTask(mBean);// 将完成信息保存至数据库  
  505.     }  
  506.   
  507.     /** 
  508.      * 出现错误时候回调 
  509.      *  
  510.      * @param info 
  511.      */  
  512.     private void callBackError(String info) {  
  513.         mState = EngineConstants.DOWNLOAD_STATE_ERROR;  
  514.         mCallback.callbackWhenDownloadTaskListener(mState, mBean, info);  
  515.         removeDownloaderInfo(mBean.url);  
  516.     }  
  517.   
  518.     /** 
  519.      * 判断SD卡上是否留有足够的空间 
  520.      */  
  521.     private boolean hasSpaceInSDCard() {  
  522.         if (mBean.fileSize > EngineUtil.getInstance().getFreeSpaceAtDirectory(  
  523.                 Environment.getExternalStorageDirectory().getAbsolutePath())) {  
  524.             callBackError("存储卡空间不够");  
  525.             return false;  
  526.         }  
  527.         return true;  
  528.     }  
  529. }  

 

欢迎吐槽,欢迎提供建议,欢迎提供改进方法。

整个架构详见源码,绝对值得你下载收藏!这一切都是免费的,对,你不要怀疑,商业级别的源码都是免费的。
如果你觉得好,请帮忙下载源码下载

源码:http://download.csdn.net/detail/h3c4lenovo/5987789

时间: 2024-10-27 13:08:54

多线程下载的相关文章

用VB编写异步多线程下载程序

程序|多线程|下载|异步 为了高效率地下载某站点的网页,我们可利用VB的Internet Transfer 控件编写自己的下载程序, Internet Transfer 控件支持超文本传输协议 (HTTP) 和文件传输协议 (FTP),使用 Internet Transfer 控件可以通过 OpenURL 或 Execute 方法连接到任何使用这两个协议的站点并检索文件.本程序使用多个Internet Transfer 控件,使其同时下载某站点.并可判断文件是否已下载过或下载过的文件是否比服务器

.Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient)

client|web|多线程|客户端|下载 /* .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient) * Reflector 了一下 System.Net.WebClient ,重载或增加了若干: * DownLoad.Upload 相关方法! * DownLoad 相关改动较大! * 增加了 DataReceive.ExceptionOccurrs 事件! * 了解服务器端与客户端交互的 HTTP 协议参阅: * 使文件

Android多线程下载

项目源码下载 https://github.com/Wang-Jun-Chao/AndroidProjects 多线程下载 原理:服务器CPU分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源 确定每条线程下载多少数据 发送http请求至下载地址 String path = URL url = new URL(path) HttpURLConnection conn = (HttpURLConnection) url() conn()

编写断点续传和多线程下载模块

本文配套源码 概述 在当今的网络时代,下载软件是使用最为频繁的软件之一.几年来,下载技术也在不停地发展.最原始的下载功能仅仅是个"下载"过程,即从WEB服务器上连续地读取文件.其最大的问题是,由于网络的不稳定性,一旦连接断开使得下载过程中断,就不得不全部从头再来一次. 随后,"断点续传"的概念就出来了,顾名思义,就是如果下载中断,在重新建立连接后,跳过已经下载的部分,而只下载还没有下载的部分. 无论"多线程下载"技术是否洪以容先生的发明,洪以容使

Java技术体验:HTTP多线程下载,端口侦听和自启动服务

一个网友正好需要这个东西,我就把几个技术整合到了一起.包括三个部分,实现时也是逐个做到的 多线程的文件下载,HTTP协议 把这个功能做成一个HTTP的服务,侦听在某个端口上,方便非Java的系统使用 把这个功能封装为一个Windows服务,在机器启动时可以自动启动 我们逐个看程序. 一.多线程下载 这个主要使用了HTTP协议里面的一个Range参数,他设置了你读取数据的其实位置和终止位置. 经常使用flashget的用户在查看连接的详细信息时,应该经常看到这个东西.比如 Range:bytes=

XP系统里让IE支持多线程下载怎么设置

  XP系统里让IE支持多线程下载怎么设置         1.使用windows快捷键"win+r"打开运行框,输入"regedit",点击"确定"即可;如下图所示: 2.在打开的注册表编辑器中依次打开HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionInternet Settings,在右边找到MaxConnectionsPer1_0Server 项;如下图所示: 3:接着双击&qu

android-Android 多线程下载APK文件,网络不稳定时,APK文件出错

问题描述 Android 多线程下载APK文件,网络不稳定时,APK文件出错 使用的是RandomAccessFile 为什么会出现这种情况? 解决方案 下载不完整,无法安装,如果你对这种通过seek去定位,然后复制字节操作不是很熟的话,建议别用RandomAccessFile,哪怕使用Android自身的DownloadManager也可以 解决方案二: 网络不稳定什么情况都有可能发上,将出错的文件和正确的文件用二进制比较工具(比如ultracomparer)比较,看看是分块的问题还是漏传了某

Serv-u FTP多线程下载 获取DOS文件目录

问题描述 用seru-u6.4实现了多线程下载,但是获取目录时,得到的目录格式为Unix格式,而且不知道如何修改.因需要统一完整的时间格式,包括年月日时分.所以改用7.0版本,不过出现了问题,我的多线程下载思路是创建多个线程,每个线程负责一个文件,现在假如创建5个线程,正常是5个线程各自下载一个,然后哪个先下载完成,继续下载未下载的文件,直至结束.但是现在出现的问题是刚开始的5个线程下载完成后,就不在下载其他的,而且停止后在连接serv-u连接不上.所以现在请各位高手,大侠帮忙解决一下,一个问题

[Unity]AssetBundle资源更新以及多线程下载

前言 此文章适合不太了解资源加载的萌新,有了入门基础之后再去github上搜大牛写的专业的资源加载方案才能得心应手,不然的话会看的很吃力或者说一脸懵逼.Unity里面关于资源加载我们都知道是下载更新AssetBundle,关于AssetBundle我之前的文章已经详细介绍过,没看过的朋友可以在看一下.下面介绍的资源加载的Demo有以下几点: 1.WWW下载图片资源 2.HTTP下载apk文件,并且支持断点续传,并且显示加载进度条 3.HTTP多线程下载文件 部分核心代码和讲解 WWW下载 思路:

http-关于用多线程下载后还需要异步下载吗?

问题描述 关于用多线程下载后还需要异步下载吗? 我们知道HTTP下载分同步和异步,当我开了一个线程去下载的时候,是不是线程同步下载就等效于直接异步下载了呢?希望能给点明确的回答,在做项目时遇到这个困扰了,谢谢大家 解决方案 你线程就是异步了,下载完了,通知主线程处理.