C# 多线程下载

下面是一个完整的多线程下载源码,我在写代码的时候遇到点问题也放在下面,希望大家别犯相同的错误。

问题1、线程偷懒?
在程序中我设置N个线程去下载时,然而有的线程却偷懒去了,当时非常奇怪,花了很多时间在代码上。
这其实是因为服务器不支持多线程下载造成的,大部分专业的下载站都禁止多线程下载,既然是服务器的原因那就没法了,在这里我想提一下在IIS7中启用和禁止多线程的方法。
应用程序池 -》 右击属性“高级设置” -》 进程模型 -》 最大工作进程数(这里便是设置允许多少线程)
至于IIS6也在应用程序池里设置,应用程序池- 》右击属性 -》 性能 -》 最大工作进程数。好了废话不说了,看下面的源码:

使用:
JhxzThreading mt = new JhxzThreading(5, “下载地址”, "本地保存路径");
mt.FileName = "wenjian"; //保存的文件名
mt.Start();

JhxzThreading公开了一些属性方便调用,如IsComplete表示这个下载任务是否完成,还有DownloadSize这个是实时下载了多少字节,通过这两个我们可以很容易实现进度条。如果有进度控件par:
pbar.Maximum = (int)mt.FileSize;
while (!mt.IsComplete)
{
    pbar.Value = mt.DownloadSize;
}

上面虽然实现进度条了,但是由于主线程一直在循环的工作,窗体可能会有假死现象,针对这个原因我们专门用一个线程来控制进度。于是有了下面的做法。

pbar.Maximum = (int)mt.FileSize;

Thread bar = new Thread(() => {

    while (!mt.IsComplete)

    {

        Thread.Sleep(50);

        this.SafeInvoke(() => { pbar.Value = mt.DownloadSize; });

    }

    MessageBox.Show("恭喜!文件已下载完成","提示",

        MessageBoxButtons.OK,MessageBoxIcon.Information);

});

bar.Start();

 

多线程下载类:

public class JhxzThreading

{

    private int _threadNum;             //线程数量

    private long _fileSize;             //文件大小

    private string _extName;            //文件扩展名

    private string _fileUrl;            //文件地址

    private string _fileName;           //文件名

    private string _savePath;           //保存路径

    private short _threadCompleteNum;   //线程完成数量

    private bool _isComplete;           //是否完成

    private volatile int _downloadSize; //当前下载大小

    private Thread[] _thread;           //线程数组

    private List<string> _tempFiles = new List<string>();

 

    public string FileName

    {

        get

        {

            return _fileName;

        }

        set

        {

            _fileName = value;

        }

    }

 

    public long FileSize

    {

        get

        {

            return _fileSize;

        }

    }

 

    public int DownloadSize

    {

        get

        {

            return _downloadSize;

        }

    }

 

    public bool IsComplete

    {

        get

        {

            return _isComplete;

        }

        set

        {

            _isComplete = value;

        }

    }

 

    public int ThreadNum

    {

        get

        {

            return _threadNum;

        }

        set

        {

            _threadNum = value;

        }

    }

 

    public string SavePath

    {

        get

        {

            return _savePath;

        }

        set

        {

            _savePath = value;

        }

    }

 

    public JhxzThreading(int threahNum, string fileUrl, string savePath)

    {

        this._threadNum = threahNum;

        this._thread = new Thread[threahNum];

        this._fileUrl = fileUrl;

        this._savePath = savePath;

    }

 

    public void Start()

    {

        HttpWebRequest request =

            (HttpWebRequest)WebRequest.Create(_fileUrl);

        HttpWebResponse response =

            (HttpWebResponse)request.GetResponse();

        //获取真实扩展名

        _extName =

            response.ResponseUri.ToString().Substring(

            response.ResponseUri.ToString().LastIndexOf('.'));

        _fileSize = response.ContentLength;

        int singelNum = (int)(_fileSize / _threadNum);      //平均分配

        int remainder = (int)(_fileSize % _threadNum);      //获取剩余的

        request.Abort();

        response.Close();

        for (int i = 0; i < _threadNum; i++)

        {

            List<int> range = new List<int>();

            range.Add(i * singelNum);

            //剩余的交给最后一个线程

            if (remainder != 0 && (_threadNum - 1) == i)   

                range.Add(i * singelNum + singelNum +

                    remainder - 1);

            else

                range.Add(i * singelNum + singelNum - 1);

            _thread[i] =

                new Thread(() => { Download(range[0], range[1]); });

            _thread[i].Name = "jhxz_{0}".Formart(i + 1);

            _thread[i].Start();

        }

    }

 

    private void Download(int from, int to)

    {

        Stream httpFileStream = null, localFileStram = null;

        try

        {

            string tmpFileBlock =

                @"{0}\{1}_{2}.dat".Formart(_savePath, _fileName,

                Thread.CurrentThread.Name);

            _tempFiles.Add(tmpFileBlock);

            HttpWebRequest httprequest =

                (HttpWebRequest)WebRequest.Create(_fileUrl);

            httprequest.AddRange(from, to);

            HttpWebResponse httpresponse =

                (HttpWebResponse)httprequest.GetResponse();

            httpFileStream = httpresponse.GetResponseStream();

            localFileStram = new FileStream(tmpFileBlock, FileMode.Create);

            byte[] by = new byte[5000];

            //Read方法将返回读入by变量中的总字节数

            int getByteSize =

                httpFileStream.Read(by, 0, (int)by.Length);          

            while (getByteSize > 0)

            {

                Thread.Sleep(20);

                _downloadSize += getByteSize;

                localFileStram.Write(by, 0, getByteSize);

                getByteSize = httpFileStream.Read(by, 0, (int)by.Length);

            }

            _threadCompleteNum++;

        }

        catch (Exception ex)

        {

            throw new Exception(ex.Message.ToString());

        }

        finally

        {

            if (httpFileStream != null) httpFileStream.Dispose();

            if (localFileStram != null) localFileStram.Dispose();

        }

        if (_threadCompleteNum == _threadNum)

        {

            _isComplete = true;

            Complete();

        }

    }

 

    private void Complete()

    {

        Stream mergeFile =

            new FileStream(@"{0}\{1}{2}".Formart(_savePath,

                _fileName, _extName), FileMode.Create);

        BinaryWriter AddWriter = new BinaryWriter(mergeFile);

        foreach (string file in _tempFiles)

        {

            using (FileStream fs = new FileStream(file, FileMode.Open))

            {

                BinaryReader TempReader = new BinaryReader(fs);

                AddWriter.Write(TempReader.ReadBytes((int)fs.Length));

                TempReader.Close();

            }

            File.Delete(file);

        }

        AddWriter.Close();

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值