NEWS

[C#] Chia sẽ Class Download file chia thành nhiều phần nhỏ để tải

[C#] Chia sẽ Class Download file chia thành nhiều phần nhỏ để tải
Đăng bởi: Thảo Meo - Lượt xem: 5001 15:54:51, 07/01/2020DEVEXPRESS   In bài viết

Xin chào các bạn, bài viết này mình sẽ tiếp tục chia sẽ đến các bạn Class Downloader.cs, dùng để download file lớn thành từng File nhỏ trong lập trình C# Winform.

[C#] Download Segment part File 

Trong các chương trình download, như ứng dụng download file nổi tiếng: Internet Download Manager.

Khi các bạn download một tập tin File lớn khoảng vài GB, thì với thiết bị máy tính hiện nay sử dụng nhiều CORE. 

Thì cách chia nhỏ file ra sử dụng Parallels download để sử dụng rất phổ biến.

Ví dụ: bạn download 1 File Windows 4GB.

Các bạn có thể tùy chỉnh tách nhỏ file thành số phần do bạn quy định. Thường mình sẽ chọn chia thành 8 phần.

Sau khi download 8 file này sau, sẽ thực hiện bước cuối cùng là nối các file temp này lại với nhau. 

Sau khi nối file download hoàn tất, thì chúng ta sẽ xóa đi những file temp này.

Trong class này File download temp sẽ được lưu trong thư mục đặc biệt special folder C:

Các bạn có thể gõ %temp%, để xem khi download.

Hình ảnh demo mình download ứng dụng Teamviewer:

split_download

Source code C# Class Download.cs

using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace SplitDownload
{
    public static class Downloader
    {
        static object MYlOCK = new object();
        static Downloader()
        {
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.DefaultConnectionLimit = 100;
            ServicePointManager.MaxServicePointIdleTime = 1000;

        }
        public static DownloadResult Download(String fileUrl, String destinationFolderPath, int numberOfParallelDownloads = 0, bool validateSSL = false)
        {
            if (!validateSSL)
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            }

            Uri uri = new Uri(fileUrl);

            //Calculate destination path  
            String destinationFilePath = Path.Combine(destinationFolderPath, uri.Segments.Last());

            DownloadResult result = new DownloadResult() { FilePath = destinationFilePath };

            //Handle number of parallel downloads  
            if (numberOfParallelDownloads <= 0)
            {
                numberOfParallelDownloads = Environment.ProcessorCount;
            }

            #region Get file size  
            WebRequest webRequest = HttpWebRequest.Create(fileUrl);
            webRequest.Method = "HEAD";
            long responseLength;
            using (WebResponse webResponse = webRequest.GetResponse())
            {
                responseLength = long.Parse(webResponse.Headers.Get("Content-Length"));
                result.Size = responseLength;
            }
            #endregion

            if (File.Exists(destinationFilePath))
            {
                File.Delete(destinationFilePath);
            }

            using (FileStream destinationStream = new FileStream(destinationFilePath, FileMode.Append))
            {
                ConcurrentDictionary<long, String> tempFilesDictionary = new ConcurrentDictionary<long, String>();

                #region Calculate ranges  
                List<Range> readRanges = new List<Range>();
                for (int chunk = 0; chunk < numberOfParallelDownloads - 1; chunk++)
                {
                    var range = new Range()
                    {
                        Start = chunk * (responseLength / numberOfParallelDownloads),
                        End = ((chunk + 1) * (responseLength / numberOfParallelDownloads)) - 1
                    };
                    readRanges.Add(range);
                }


                readRanges.Add(new Range()
                {
                    Start = readRanges.Any() ? readRanges.Last().End + 1 : 0,
                    End = responseLength - 1
                });

                #endregion

                DateTime startTime = DateTime.Now;

                #region Parallel download  

                int index = 0;
                Parallel.ForEach(readRanges, new ParallelOptions() { MaxDegreeOfParallelism = numberOfParallelDownloads }, readRange =>
                {
                    HttpWebRequest httpWebRequest = HttpWebRequest.Create(fileUrl) as HttpWebRequest;
                    httpWebRequest.Method = "GET";
                    httpWebRequest.AddRange(readRange.Start, readRange.End);
                    using (HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse)
                    {
                        String tempFilePath = Path.GetTempFileName();                      
                        using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.Write))
                        {
                            

                            httpWebResponse.GetResponseStream().CopyTo(fileStream);
                            lock (Downloader.MYlOCK)
                            {
                                result.PROGRESS += fileStream.Length;
                                var percent = 1.0 * result.PROGRESS / result.Size;
                                Debug.WriteLine("Progress: " + percent);
                            }
                            tempFilesDictionary.TryAdd(readRange.Start, tempFilePath);
                        }
                    }
                    index++;

                });

                result.ParallelDownloads = index;

                #endregion

                result.TimeTaken = DateTime.Now.Subtract(startTime);

                #region Merge to single file  
                foreach (var tempFile in tempFilesDictionary.OrderBy(b => b.Key))
                {
                    byte[] tempFileBytes = File.ReadAllBytes(tempFile.Value);
                    destinationStream.Write(tempFileBytes, 0, tempFileBytes.Length);
                    File.Delete(tempFile.Value);
                }
                #endregion


                return result;
            }


        }
    }
    internal class Range
    {
        public long Start { get; set; }
        public long End { get; set; }
    }

    public class DownloadResult
    {
        public long Size { get; set; }
        public String FilePath { get; set; }
        public TimeSpan TimeTaken { get; set; }
        public int ParallelDownloads { get; set; }

        public long PROGRESS { get; set; }
    }

}

Để sử dụng trong form Main.cs các bạn chạy lệnh sau:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SplitDownload
{
    public partial class Form1 : Form
    {


        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(new Action(() => {
                //SplitDownload(textBox1.Text);
                var result = Downloader.Download(textBox1.Text, @"", 16);

                Debug.WriteLine($"=============================================================");

                Debug.WriteLine($"Location: {result.FilePath}");
                Debug.WriteLine($"Size: {result.Size}bytes");
                Debug.WriteLine($"Time taken: {result.TimeTaken.Milliseconds}ms");
                Debug.WriteLine($"Parallel: {result.ParallelDownloads}");
                Debug.WriteLine($"=============================================================");


            }));
        }

       


    }
}

Thanks for watching!

 

DOWNLOAD SOURCE

THÔNG TIN TÁC GIẢ

BÀI VIẾT LIÊN QUAN

[C#] Chia sẽ Class Download file chia thành nhiều phần nhỏ để tải
Đăng bởi: Thảo Meo - Lượt xem: 5001 15:54:51, 07/01/2020DEVEXPRESS   In bài viết

CÁC BÀI CÙNG CHỦ ĐỀ

Đọc tiếp
.