- [DEVEXPRESS] Đặt mật khẩu và bỏ mật khẩu tập tin file PDF
- [C#] Thêm ứng dụng vào Taskbar sử dụng SharpShell DeskBand
- [C#] Hướng dẫn thêm text vào hình ảnh icon winform
- [C#] Chia sẽ tổng hợp source code đồ án về Csharp
- [C#] Hướng dẫn viết ứng dụng quay màn hình video winform, Screen Recorder
- [C#] Hướng dẫn sử dụng thư viện Input Simulator để làm việc với Keyboard, Mouse Virtual
- [DEVEXPRESS] Hướng dẫn tích Filter Contain khi click chuột phải vào cell selection trên Gridview
- [C#] Tra cứu mã số thuế cá nhân bằng CMND hoặc CCCD
- [C#] Convert hình ảnh image thành Blurhash sử dụng trong loading image winform
- [POWERSHELL] Script sao lưu backup và nén database sqlserver
- [C#] Giới thiệu thư viện Autofac Dependency Injection
- [C#] Hướng dẫn tạo Windows Services đơn giản Winform
- [C#] Một click chuột điều khiển máy tính từ xa sử dụng Ultraviewer
- Hướng dẫn đóng gói phần mềm sử dụng Powershell biên dịch script thành file exe
- [C#] Hướng dẫn sử dụng Task Dialog trên NET 5
- [C#] Hướng dẫn xem lịch sử các trang web đã truy cập trên Chrome Browser
- [C#] Hướng dẫn lấy thông tin Your ID và Password của Ultraviewer Winform
- [C#] Hướng dẫn lấy thông tin Your ID và Password của Teamviewer Winform
- [C#] Hướng dẫn build code động xuất file exe trên Winform
- [C#] Điều khiển ứng dụng từ xa và rất xa với Telegram Bot 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!