C#:如何通过WebClient下载含内容的文件夹并保留目录结构?
使用C# WebClient下载文件夹并保留目录结构
需求说明
目前已实现用WebClient下载单个文件,现在需要扩展功能:下载远程服务器上的整个文件夹,同时保留指定的目录结构。
- 下载前本地目录结构:
MyprojectApp/Test.exe - 期望下载后本地目录结构:
MyprojectApp/Test.exe MyprojectApp/New/some.txt
当前单个文件下载代码:
WebClient wc = new WebClient(); String Filename = "some.txt"; Uri uri = new Uri("http://127.0.0.1/New/" + Filename); wc.DownloadFileAsync(uri, "some1.txt");
实现思路
WebClient本身不支持直接下载文件夹,需要手动实现以下步骤:
- 获取远程目标目录下的所有文件路径列表(需服务器支持目录访问,比如IIS开启目录浏览,或提供接口返回文件清单)
- 遍历每个远程文件,解析出相对路径,在本地创建对应的目录结构
- 逐个异步下载文件到本地对应路径
代码实现
以下是完整的实现代码,包含目录创建、异步下载及基本异常处理:
using System; using System.IO; using System.Net; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading.Tasks; public class FolderDownloader { private readonly string _remoteRootUrl; private readonly string _localRootPath; private readonly WebClient _webClient; public FolderDownloader(string remoteRootUrl, string localRootPath) { _remoteRootUrl = remoteRootUrl.EndsWith("/") ? remoteRootUrl : remoteRootUrl + "/"; _localRootPath = Path.GetFullPath(localRootPath); _webClient = new WebClient(); _webClient.DownloadFileCompleted += OnDownloadFileCompleted; } public async void StartFolderDownload() { try { // 获取远程目录的HTML列表,需根据服务器返回格式调整解析逻辑 string dirHtml = await _webClient.DownloadStringTaskAsync(_remoteRootUrl); List<string> remoteFiles = ParseRemoteFileList(dirHtml); foreach (string file in remoteFiles) { Uri remoteUri = new Uri(_remoteRootUrl + file); string localFilePath = Path.Combine(_localRootPath, file); // 创建本地目录 string localDir = Path.GetDirectoryName(localFilePath); if (!Directory.Exists(localDir)) { Directory.CreateDirectory(localDir); } // 异步下载文件 await _webClient.DownloadFileTaskAsync(remoteUri, localFilePath); } } catch (Exception ex) { Console.WriteLine($"下载出错:{ex.Message}"); } } // 解析服务器返回的HTML目录列表(示例逻辑,需根据实际HTML结构调整) private List<string> ParseRemoteFileList(string dirHtml) { List<string> filePaths = new List<string>(); // 匹配HTML中的文件链接,排除上级目录和当前目录的跳转链接 Regex linkRegex = new Regex(@"<a href=""([^""../]+)"""); MatchCollection matches = linkRegex.Matches(dirHtml); foreach (Match match in matches) { string filePath = match.Groups[1].Value; // 过滤目录链接(如果服务器返回的目录链接有标识,可在此处判断) if (!filePath.EndsWith("/")) { filePaths.Add(filePath); } } return filePaths; } // 单个文件下载完成的回调 private void OnDownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (e.Error != null) { Console.WriteLine($"文件下载失败:{e.Error.Message}"); } else if (e.Cancelled) { Console.WriteLine("下载已取消"); } else { Console.WriteLine("单个文件下载完成"); } } } // 使用示例 class Program { static void Main(string[] args) { FolderDownloader downloader = new FolderDownloader("http://127.0.0.1/New/", "MyprojectApp/"); downloader.StartFolderDownload(); // 保持程序运行以等待异步任务完成 Console.ReadLine(); } }
注意事项
- 服务器配置:远程服务器必须允许目录内容访问,比如IIS需开启「目录浏览」;如果是自定义服务,需提供接口返回目标目录的文件清单
- 解析逻辑适配:
ParseRemoteFileList方法的正则逻辑仅为示例,实际需根据服务器返回的HTML结构调整,建议使用HTML解析库(如HtmlAgilityPack)替代正则,提升稳定性 - 异常处理:实际使用时需补充网络中断、权限不足等更多异常场景的处理逻辑
- 异步任务管理:示例中用
Console.ReadLine()维持程序运行,实际项目中需根据上下文合理处理异步任务的等待逻辑
内容的提问来源于stack exchange,提问作者Goutham Jr
相关产品推荐
相关产品推荐

