以下方法的优势:
- 高效性:采用
HttpClient
进行异步请求,减少了线程阻塞,提高下载速度,使用缓冲区分块读取和写入文件,避免一次性加载整个文件,节省内存。 - 提升用户体验:实时输出下载进度,用户可以清楚地了解下载的状态,提升用户体验。
- 支持大文件下载:将下载功能封装在静态方法中,便于在不同项目或场景中重复使用。
using System; // 引入基础功能的命名空间
using System.Net.Http; // 引入处理HTTP请求的命名空间
using System.Threading.Tasks; // 引入处理异步任务的命名空间
using System.IO; // 引入处理文件输入输出的命名空间
public class FileDownloader
{
// 静态HttpClient实例,用于发起HTTP请求,避免多次创建带来的开销
private static readonly HttpClient httpClient = new HttpClient();
// 异步方法,用于下载文件,接受URL和目标路径作为参数
public static async Task DownloadFileAsync(string url, string destinationPath)
{
// 检查URL是否为空或只包含空白字符,如果是则抛出异常
if (string.IsNullOrWhiteSpace(url))
throw new ArgumentException("URL 不能为 null 或空", nameof(url));
// 检查目标路径是否为空或只包含空白字符,如果是则抛出异常
if (string.IsNullOrWhiteSpace(destinationPath))
throw new ArgumentException("目标路径不能为 null 或为空", nameof(destinationPath));
try
{
// 发送GET请求以获取指定URL的响应,设置为只读取响应头
using (HttpResponseMessage response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
// 确保响应是成功的状态码
response.EnsureSuccessStatusCode();
// 获取文件的总大小,以便进行切片下载
long totalBytes = response.Content.Headers.ContentLength ?? -1;
const int bufferSize = 8192; // 定义缓冲区大小为8KB
byte[] buffer = new byte[bufferSize]; // 创建缓冲区以存储下载的数据
// 使用FileStream异步创建文件流并写入文件
using (Stream contentStream = await response.Content.ReadAsStreamAsync(),
fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize, useAsync: true))
{
long totalReadBytes = 0; // 记录已读取的字节数
int bytesRead; // 当前读取的字节数
// 循环读取数据直到内容流结束
while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// 将缓冲区中的数据写入文件流
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalReadBytes += bytesRead; // 更新已读取的字节数
// 输出下载进度
if (totalBytes > 0)
{
Console.WriteLine($"下载{totalReadBytes} of {totalBytes} 字节.");
}
}
}
}
}
catch (Exception ex)
{
// 捕获并输出异常信息,然后重新抛出异常
Console.WriteLine($"错误: {ex.Message}");
throw;
}
}
}