- [SQLSERVER] Loại bỏ Restricted User trên database MSSQL
- [C#] Hướng dẫn tạo mã QRcode Style trên winform
- [C#] Hướng dẫn sử dụng temp mail service api trên winform
- [C#] Hướng dẫn tạo mã thanh toán VietQR Pay không sử dụng API trên winform
- [C#] Hướng Dẫn Tạo Windows Service Đơn Giản Bằng Topshelf
- [C#] Chia sẻ source code đọc dữ liệu từ Google Sheet trên winform
- [C#] Chia sẻ source code tạo mã QR MOMO đa năng Winform
- [C#] Chia sẻ source code phần mềm lên lịch tự động chạy ứng dụng Scheduler Task Winform
- [Phần mềm] Tải và cài đặt phần mềm Sublime Text 4180 full version
- [C#] Hướng dẫn download file từ Minio Server Winform
- [C#] Hướng dẫn đăng nhập zalo login sử dụng API v4 trên winform
- [SOFTWARE] Phần mềm gởi tin nhắn Zalo Marketing Pro giá rẻ mềm nhất thị trường
- [C#] Việt hóa Text Button trên MessageBox Dialog Winform
- [DEVEXPRESS] Chia sẻ code các tạo report in nhiều hóa đơn trên XtraReport C#
- [POWER AUTOMATE] Hướng dẫn gởi tin nhắn zalo từ file Excel - No code
- [C#] Chia sẻ code lock và unlock user trong domain Window
- [DEVEXPRESS] Vẽ Biểu Đồ Stock Chứng Khoán - Công Cụ Thiết Yếu Cho Nhà Đầu Tư trên Winform
- [C#] Hướng dẫn bảo mật ứng dụng 2FA (Multi-factor Authentication) trên Winform
- [C#] Hướng dẫn convert HTML code sang PDF File trên NetCore 7 Winform
- [C#] Hướng dẫn viết ứng dụng chat với Gemini AI Google Winform
[C#] Chia sẽ Class Download file chia thành nhiều phần nhỏ để tải
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:
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!