You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中如何优雅地从文件服务器URI批量复制文件到本地

优雅地从HTTP文件服务器下载目录下所有文件到本地(.NET 6)

情况1:文件服务器支持WebDAV协议

如果你的文件服务器支持WebDAV(比如IIS配置了WebDAV扩展、Apache开启mod_dav等),这是最优雅的解决方案——不需要解析HTML,直接通过WebDAV协议枚举文件并下载。

实现代码

using System.Net.Http;
using System.Xml.Linq;

public static async Task DownloadFilesViaWebDavAsync(string sourceUrl, string targetDir)
{
    // 确保本地目标目录存在
    Directory.CreateDirectory(targetDir);
    
    using var httpClient = new HttpClient();
    // 发送PROPFIND请求获取当前目录的文件列表
    var propfindRequest = new HttpRequestMessage(HttpMethod.Propfind, sourceUrl);
    propfindRequest.Headers.Add("Depth", "1"); // 仅获取当前层级的内容,不递归子目录
    
    var response = await httpClient.SendAsync(propfindRequest);
    response.EnsureSuccessStatusCode(); // 确保请求成功
    
    var xmlContent = await response.Content.ReadAsStringAsync();
    var xmlDoc = XDocument.Parse(xmlContent);
    
    var davNamespace = XNamespace.Get("DAV:");
    
    // 遍历所有文件条目,排除目录项
    foreach (var responseElement in xmlDoc.Descendants(davNamespace + "response"))
    {
        var fileHref = responseElement.Element(davNamespace + "href")?.Value;
        if (string.IsNullOrWhiteSpace(fileHref)) continue;
        
        // 跳过目录链接(以上斜杠结尾的都是目录)
        if (fileHref.EndsWith("/")) continue;
        
        // 构建完整的文件下载URL
        var fullFileUrl = new Uri(new Uri(sourceUrl), fileHref).ToString();
        var fileName = Path.GetFileName(fileHref);
        var localFilePath = Path.Combine(targetDir, fileName);
        
        // 下载并保存文件
        using var localFileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.Write);
        await httpClient.GetStreamAsync(fullFileUrl).CopyToAsync(localFileStream);
    }
}

情况2:文件服务器仅返回HTML目录列表

如果服务器只能返回默认的HTML索引页面(就像你遇到的情况),用专业的HTML解析库替代手写正则,代码更可靠、易维护。

步骤1:安装AngleSharp NuGet包

先在项目中安装AngleSharp(一款轻量且强大的HTML解析库):

Install-Package AngleSharp

实现代码

using AngleSharp;
using AngleSharp.Dom;
using System.Net.Http;

public static async Task DownloadFilesFromHtmlIndexAsync(string sourceUrl, string targetDir)
{
    Directory.CreateDirectory(targetDir);
    
    using var httpClient = new HttpClient();
    var htmlPageContent = await httpClient.GetStringAsync(sourceUrl);
    
    // 初始化AngleSharp的解析环境
    var browsingContext = BrowsingContext.New(Configuration.Default);
    var htmlDocument = await browsingContext.OpenAsync(req => req.Content(htmlPageContent));
    
    // 提取所有文件链接:排除上级目录(../)和子目录(以/结尾)
    var fileLinks = htmlDocument.QuerySelectorAll("pre a")
        .Where(linkElement => 
            !linkElement.GetAttribute("href").StartsWith("../") 
            && !linkElement.GetAttribute("href").EndsWith("/"))
        .Select(linkElement => linkElement.GetAttribute("href"));
    
    foreach (var relativeFilePath in fileLinks)
    {
        var fullFileUrl = new Uri(new Uri(sourceUrl), relativeFilePath).ToString();
        var fileName = Path.GetFileName(relativeFilePath);
        var localFilePath = Path.Combine(targetDir, fileName);
        
        // 下载文件到本地
        using var localFileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.Write);
        await httpClient.GetStreamAsync(fullFileUrl).CopyToAsync(localFileStream);
    }
}

额外优化建议

  • 异常处理:可以添加try-catch块处理单个文件下载失败的情况,避免整个任务中断
  • 并行下载:使用.NET 6+支持的Parallel.ForEachAsync实现多文件并行下载,提升效率(注意控制并发数,避免压垮服务器)
  • 覆盖控制:可以判断本地文件是否存在,按需跳过或覆盖
  • 进度跟踪:如果需要显示下载进度,可使用HttpCompletionOption.ResponseHeadersRead配合流读取来实现实时进度更新

内容的提问来源于stack exchange,提问作者CrazyEight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 01:38:09