c#多线程下载方案

using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

class HttpMultiThreadDownload
{
    const int _bufferSize = 1024 * 16;
    public DownLoadForm Form { get; set; }
    //线程ID   
    public int ThreadID { get; set; }
    //文件URI
    public string URI { get; set; }
    //线程回调
    Action<DownloadState, float> Callback = null;

    public HttpMultiThreadDownload(DownLoadForm form, int threadID, Action<DownloadState, float> callback)
    {
        Form = form;
        ThreadID = threadID;
        URI = form.SourceURI;
        Callback = callback;
    }

    //析构方法
    ~HttpMultiThreadDownload()
    {
        Form.Dispose();
    }

    public void Receive()
    {
        //线程临时文件
        string fileName = Form.fileNames[ThreadID];
        //接收缓冲区
        byte[] buffer = new byte[_bufferSize];
        //接收字节数
        int readSize = 0;
        Stream stream = null;
        //Log.LogDebug.Print("   线程[" + ThreadID.ToString() + "] 开始接收......");
        while (true)
        {
            if (!Form.isPause)
            {
                using (FileStream fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
                {
                    try
                    {
                        long currentLen = fileStream.Length;
                        Form.hasReceived[ThreadID] = (int)currentLen;
                        Form.restartPos[ThreadID] = Form.startPos[ThreadID] + Form.hasReceived[ThreadID];
                        fileStream.Seek(Form.hasReceived[ThreadID], SeekOrigin.Begin);//seek
                        HttpWebRequest request;
                        if (URI.StartsWith("https", StringComparison.OrdinalIgnoreCase))//https
                        {
                            ServicePointManager.ServerCertificateValidationCallback
                                = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
                                => { return true; });
                            request = (HttpWebRequest)WebRequest.Create(URI);
                            request.ProtocolVersion = HttpVersion.Version11;
                        }
                        else {//http
                            request = (HttpWebRequest)WebRequest.Create(URI);
                        }
                        request.AddRange(Form.restartPos[ThreadID], Form.startPos[ThreadID] + Form.fileSize[ThreadID]);//seek
                        stream = request.GetResponse().GetResponseStream();
                        readSize = stream.Read(buffer, 0, _bufferSize);
                        while (!Form.isPause && readSize > 0)
                        {
                            Handle(DownloadState.Downloading);
                            fileStream.Write(buffer, 0, readSize);
                            Form.hasReceived[ThreadID] += readSize;
                            readSize = stream.Read(buffer, 0, _bufferSize);
                            //Thread.Sleep(100);//下载优化
                        }
                        Form.restartPos[ThreadID] = Form.startPos[ThreadID] + Form.hasReceived[ThreadID];
                        stream.Close();
                    }
                    catch (Exception ex)
                    {
                        //Log.LogDebug.PrintError(ex.Message);
                        break;
                    }
                }
            }
            if (Form.hasReceived[ThreadID] >= Form.fileSize[ThreadID] + 1)
            {
                break;
            }
        }
        Form.threadIsEnd[ThreadID] = true;
        //Log.LogDebug.Print("   线程[" + ThreadID.ToString() + "] 结束");
    }

    //线程回调
    private void Handle(DownloadState state)
    {
        int tempValue = 0;
        for (int i = 0; i < Form.threadNum; i++)
        {
            tempValue += Form.hasReceived[i];
        }
        Callback?.Invoke(state, ((float)tempValue / Form.totalSize));
    }
}
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public struct DownUnit              //下载单元
{
    public string downUrl;          //下载地址
    public string downTempPath;     //临时地址
    public string downSavePath;     //保存地址
    public int RetryTimes;          //重试次数
};
public class DownLoadForm
{
    // 定义并启动线程数组
    System.Threading.Thread[] threads = null;
    HttpMultiThreadDownload[] httpDownloads = null;
    //下载文件URI
    public string SourceURI = null;
    //保存文件名
    public string TargetFileName = null;
    //是否暂停
    public volatile bool isPause = false;
    //是否首次下载
    public bool first = true;
    //线程数
    public int threadNum = 4;
    //每个线程接收文件的大小
    public int[] fileSize { get; set; }
    //每个线程已经接收文件的大小
    public int[] hasReceived { get; set; }
    //每个线程接收文件的文件名
    public string[] fileNames { get; set; }
    //每个线程接收文件的起始位置
    public int[] startPos { get; set; }
    //每个线程继续接收文件的位置
    public int[] restartPos { get; set; }
    //每个线程结束标志
    public bool[] threadIsEnd { get; set; }
    //文件合并标志
    public bool canMerge { get; set; }
    //文件总数
    public long totalSize = 0;
    //下载回调
    Action<DownloadState, float> Callback = null;

    public DownLoadForm()
    {
    }

    //点击下载按钮
    public void DownloadFile(DownUnit unit, Action<DownloadState, float> callback)
    {
        Callback = callback;
        isPause = false;
        SourceURI = unit.downUrl;
        TargetFileName = unit.downSavePath;
        HttpWebRequest request;
        totalSize = 0;
        try
        {
            if (first)
            {
                //Print(DateTime.Now.ToString() + "  开始下载 " + SourceURI);
                if (SourceURI.StartsWith("https", StringComparison.OrdinalIgnoreCase))//https
                {
                    ServicePointManager.ServerCertificateValidationCallback
                        = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
                        => { return true; });
                    request = (HttpWebRequest)WebRequest.Create(SourceURI);
                    request.ProtocolVersion = HttpVersion.Version11;
                }
                else {//http
                    request = (HttpWebRequest)WebRequest.Create(SourceURI);
                }
                totalSize = request.GetResponse().ContentLength;
                //Print("文件字节数:" + totalSize);
                request.Abort();
                Init(totalSize);
                threads = new System.Threading.Thread[threadNum];
                httpDownloads = new HttpMultiThreadDownload[threadNum];
                for (int i = 0; i < threadNum; i++)
                {
                    httpDownloads[i] = new HttpMultiThreadDownload(this, i, callback);
                    threads[i] = new System.Threading.Thread(new System.Threading.ThreadStart(httpDownloads[i].Receive));
                    threads[i].Start();
                }
                System.Threading.Thread merge = new System.Threading.Thread(new System.Threading.ThreadStart(MergeFile));
                merge.Start();
            }
            else
            {
                //Print(DateTime.Now.ToString() + "  继续下载");
            }
        }
        catch (Exception ex)
        {
            //Debug.LogError(ex.Message);
        }

    }

    //分配线程:每个线程平均分配文件大小,剩余部分由最后一个线程完成
    private void Init(long totalSize)
    {
        fileNames = new string[threadNum];
        startPos = new int[threadNum];
        restartPos = new int[threadNum];
        fileSize = new int[threadNum];
        hasReceived = new int[threadNum];
        threadIsEnd = new bool[threadNum];
        int size = (int)totalSize / threadNum;
        int endSize = size + (int)totalSize % threadNum;
        for (int i = 0; i < threadNum; i++)
        {
            fileNames[i] = TargetFileName + i.ToString() + ".dat";
            startPos[i] = size * i;
            restartPos[i] = size * i;
            fileSize[i] = (i < threadNum - 1) ? (size - 1) : (endSize - 1);
            hasReceived[i] = 0;
            threadIsEnd[i] = false;
        }
    }

    //合并文件
    public void MergeFile()
    {
        while (true)
        {
            canMerge = true;
            for (int i = 0; i < threadNum; i++)
            {
                //若有未结束线程,则等待
                if (!threadIsEnd[i])
                {
                    canMerge = false;
                    System.Threading.Thread.Sleep(100);
                    break;
                }
            }
            if (canMerge == true)
                break;
        }
        int bufferSize = 1024 * 16;
        int readSize;
        byte[] bytes = new byte[bufferSize];
        FileStream fileStream = new FileStream(TargetFileName, FileMode.OpenOrCreate);
        FileStream tempStream = null;
        for (int k = 0; k < threadNum; k++)
        {
            tempStream = new FileStream(fileNames[k], FileMode.Open);
            while (true)
            {
                readSize = tempStream.Read(bytes, 0, bufferSize);
                if (readSize > 0)
                    fileStream.Write(bytes, 0, readSize);
                else
                    break;
            }
            tempStream.Close();
            //删除临时文件
            File.Delete(fileNames[k]);
        }
        fileStream.Close();
        Callback?.Invoke(DownloadState.DownloadSucceed, 1);
        //Print(DateTime.Now.ToString() + " 下载完成, 保存于 " + TargetFileName);
    }

    public void Dispose()
    {
        isPause = true;
        first = false;
        foreach (var item in threads)
        {
            if (item != null && item.IsAlive)
            {
                item.Abort();
            }
        }
    }

    public void Stop()
    {
        isPause = true;
        first = false;
    }

    public void ReStart()
    {
        isPause = false;
        first = false;
    }
}

猜你喜欢

转载自blog.csdn.net/Momo_Da/article/details/107392739
今日推荐