多线程下载文件

作者:追风剑情 发布于:2016-6-30 10:33 分类:C#

示例代码

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;

namespace ThreadPoolTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //此值默认为2(即,同时只能有2条http并发请求),这句必须在使用Http请求前加上,才能修改并发请求数。
            ServicePointManager.DefaultConnectionLimit = 200;
            //显示CPU内核数
            Console.WriteLine("Environment.ProcessorCount={0}", Environment.ProcessorCount);

            string url = "http://192.168.1.211/trunk_pc_res/sgzs_voice.apk";
            int threadCount = Environment.ProcessorCount * 2; //线程数
            long fileSize = 0;   //文件大小(单位: byte)
            
            //获取文件大小
            HttpWebRequest web_req = (HttpWebRequest)WebRequest.Create(url);
            HttpWebResponse web_resp = (HttpWebResponse)web_req.GetResponse();
            fileSize = web_resp.ContentLength;
            web_resp.Close();
            web_req.Abort();

            //计算文件分块
            int blockSize = (int)(fileSize / threadCount);  //平均分配
            int remainSize = (int)(fileSize % threadCount); //获取剩余的

            Console.WriteLine("文件总长度: {0}, 分块长度: {1}, 剩余长度: {2}, 下载线程数: {3}", fileSize, blockSize, remainSize, threadCount);

            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            try
            {
                HttpBlockDownFile.manualResetEvent = manualResetEvent;
                HttpBlockDownFile.threadMaxCount = threadCount;
                HttpBlockDownFile.threadCompleteCount = 0;
                HttpBlockDownFile.isCompleted = false;
                HttpBlockDownFile.downLoadSize = 0;
                HttpBlockDownFile.startTime = DateTime.Now;
                HttpBlockDownFile.mergeFileName = @"D:\\sgzs.apk";
                ThreadPool.SetMaxThreads(100, 100);
                ThreadPool.SetMinThreads(10, 10);
                int from, to=0;
                for (int i = 0; i < threadCount; i++)
                {
                    from = i * blockSize;
                    to = from + blockSize - 1;
                    if (i == threadCount - 1)
                        to += remainSize;

                    HttpBlockDownFile http = new HttpBlockDownFile();
                    http.index = i;
                    http.url = url;
                    http.from = from;
                    http.to = to;
                    bool b = ThreadPool.QueueUserWorkItem(new WaitCallback(http.Run));
                    Console.WriteLine("启动线程 ID={0}, success={1} 负责下载[{2}, {3}]", i, b, from, to);
                }
            }
            catch (NotSupportedException)
            {
                Console.WriteLine("These API's may fail when called on a non-Wind ows 2000 system.");
            }

            Console.Read();
        }
    }

    class HttpBlockDownFile
    {
        //最大线程数
        public static int threadMaxCount = 0;
        //完成线程数
        public static int threadCompleteCount = 0;
        //合并文件名
        public static string mergeFileName;
        //临时文件名格式
        public static string tmpFileFormat = @"D:\\sgzs_{0}.tmp";
        //当前已下载字节数
        public static volatile int downLoadSize = 0;
        //是否下载完成
        public static bool isCompleted = false;

        public static ManualResetEvent manualResetEvent;
        public static DateTime startTime;

        public int index;
        //下载地址
        public string url;
        //开始位置
        public int from;
        //结束位置
        public int to;

        public void Run(Object state)
        {
            try
            {
                DateTime start_time = DateTime.Now;
                FileStream f = new FileStream(string.Format(tmpFileFormat, index), FileMode.Create);
                HttpWebRequest web_req = (HttpWebRequest)WebRequest.Create(url);
                web_req.AddRange(from, to);
                web_req.KeepAlive = false;
                web_req.Timeout = 10000;

                HttpWebResponse web_resp = (HttpWebResponse)web_req.GetResponse();
                long contentLength = web_resp.ContentLength;
                byte[] read_bytes = new byte[1024*10];
                int read_size = web_resp.GetResponseStream().Read(read_bytes, 0, read_bytes.Length);
                int down_size = 0;
                while(read_size > 0){
                    //Console.WriteLine("index={0}, down_size={1}, downLoadSize={2}", index, down_size, downLoadSize);
                    Thread.Sleep(1);
                    f.Write(read_bytes, 0, read_size);
                    down_size += read_size;
                    downLoadSize += read_size;
                    read_size = web_resp.GetResponseStream().Read(read_bytes, 0, read_bytes.Length);
                }
                web_resp.Close();
                web_req.Abort();
                f.Flush(true);
                f.Close();

                TimeSpan span = DateTime.Now - start_time;

                Console.WriteLine("文件块下载完成: total: {0}, down_size: {1}, from: {2}, to: {3}, 耗时{4}秒, index={5}", contentLength, down_size, from, to, span.TotalSeconds, index);

                Interlocked.Increment(ref threadCompleteCount);
                Console.WriteLine("threadCompleteCount: " + threadCompleteCount);

                if (threadMaxCount == threadCompleteCount)
                {
                    Complete();
                    manualResetEvent.Set();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private void Complete()
        {
            Console.WriteLine("Complete()");
            TimeSpan span = DateTime.Now - startTime;
            Console.WriteLine("文件下载完成! 耗时{0}秒", span.TotalSeconds);

            Console.WriteLine("开始合并文件...");

            Stream mergeFile = new FileStream(mergeFileName, FileMode.Create);
            BinaryWriter mergeWriter = new BinaryWriter(mergeFile);
            for (int i = 0; i < threadMaxCount; i++)
            {
                string tmpFileName = string.Format(tmpFileFormat, i);
                using (FileStream fs = new FileStream(tmpFileName, FileMode.Open))
                {
                    BinaryReader tempReader = new BinaryReader(fs);
                    mergeWriter.Write(tempReader.ReadBytes((int)fs.Length));
                    tempReader.Close();
                }
                File.Delete(tmpFileName);
            }
            mergeWriter.Close();
            isCompleted = true;

            Console.WriteLine("文件合并完成 " + mergeFileName);
        }
    }
}

 

运行测试1111.png

 

标签: C#

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号