前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >AspNetCore中的文件上传与下载优化

AspNetCore中的文件上传与下载优化

作者头像
郑子铭
发布2025-05-12 11:10:14
发布2025-05-12 11:10:14
14200
代码可运行
举报
运行总次数:0
代码可运行

在现代Web开发中,文件上传和下载是常见的功能需求。然而,随着文件大小的增加或网络环境的变化,传统的文件上传和下载方式可能会遇到性能瓶颈或用户体验问题。本文将深入讲解如何在AspNetCore中实现大文件上传、分块上传、断点续传以及高效的文件下载。

一、大文件上传

1. 传统方式的问题

传统的文件上传方式通常是将整个文件一次性上传到服务器。这种方式在处理小文件时表现良好,但对于大文件(如视频、文档等),可能会导致以下问题:

  • 内存占用高:如果文件过大,可能会导致服务器内存不足。
  • 网络不稳定:在网络中断的情况下,用户需要重新上传整个文件。

2. 解决方案

为了优化大文件上传,可以采用以下策略:

  • 调整请求大小限制:修改AspNetCore默认的请求大小限制。
  • 流式上传:通过流式处理避免将整个文件加载到内存中。
调整请求大小限制

Startup.cs中配置最大请求大小:

代码语言:javascript
代码运行次数:0
运行
复制
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<IISServerOptions>(options =>
    {
        options.MaxRequestBodySize = int.MaxValue; // 设置最大请求大小
    });
}
流式上传

使用IFormFile结合流式处理:

代码语言:javascript
代码运行次数:0
运行
复制
[HttpPost("upload")]
public async Task<IActionResult> UploadLargeFile(IFormFile file)
{
    if (file == null || file.Length == 0)
        return BadRequest("未选择文件");

    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "uploads", file.FileName);

    using (var stream = new FileStream(filePath, FileMode.Create))
    {
        await file.CopyToAsync(stream); // 使用流式处理
    }

    return Ok("文件上传成功");
}

二、分块上传

1. 什么是分块上传?

分块上传是指将一个大文件分割成多个小块,逐块上传到服务器。这种方式可以有效解决大文件上传时的内存占用和网络中断问题。

2. 实现步骤

  • 前端分块:将文件分割成固定大小的小块。
  • 后端合并:接收所有小块后,按顺序合并为完整文件。
前端分块

使用JavaScript实现分块上传:

代码语言:javascript
代码运行次数:0
运行
复制
function uploadFile(file) {
    const chunkSize = 1 * 1024 * 1024; // 每块1MB
    let start = 0;
    let end = chunkSize;

    functionuploadChunk() {
        if (start >= file.size) return;

        const chunk = file.slice(start, end);
        const formData = newFormData();
        formData.append('chunk', chunk);
        formData.append('fileName', file.name);

        fetch('/api/upload/chunk', {
            method: 'POST',
            body: formData
        }).then(() => {
            start = end;
            end += chunkSize;
            uploadChunk(); // 递归上传下一小块
        });
    }

    uploadChunk();
}
后端合并

接收分块并合并为完整文件:

代码语言:javascript
代码运行次数:0
运行
复制
private staticreadonly Dictionary<string, List<byte[]>> chunks = new();

[HttpPost("chunk")]
public IActionResult UploadChunk([FromForm] byte[] chunk, [FromForm] string fileName)
{
    if (!chunks.ContainsKey(fileName))
        chunks[fileName] = new List<byte[]>();

    chunks[fileName].Add(chunk);

    return Ok("分块上传成功");
}

[HttpPost("merge")]
public IActionResult MergeChunks([FromForm] string fileName)
{
    if (!chunks.ContainsKey(fileName))
        return NotFound("分块不存在");

    var allBytes = chunks[fileName].SelectMany(c => c).ToArray();
    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "uploads", fileName);

    System.IO.File.WriteAllBytes(filePath, allBytes);
    chunks.Remove(fileName);

    return Ok("文件合并成功");
}

三、断点续传

1. 什么是断点续传?

断点续传是指在网络中断或其他原因导致上传中断时,可以从上次中断的位置继续上传,而无需重新上传整个文件。

2. 实现步骤

  • 记录上传进度:在每次上传分块时,记录已上传的分块信息。
  • 恢复上传:根据记录的进度,跳过已上传的部分,继续上传剩余部分。
记录上传进度

在数据库或文件系统中记录每个分块的状态:

代码语言:javascript
代码运行次数:0
运行
复制
public class UploadProgress
{
    public string FileName { get; set; }
    public int TotalChunks { get; set; }
    public List<bool> UploadedChunks { get; set; } = new();
}
恢复上传逻辑

在上传前检查已上传的分块:

代码语言:javascript
代码运行次数:0
运行
复制
[HttpGet("progress/{fileName}")]
public IActionResult GetUploadProgress(string fileName)
{
    // 查询数据库或文件系统获取上传进度
    var progress = GetProgressFromDatabase(fileName);

    return Ok(progress);
}

四、高效的文件下载

1. 传统方式的问题

传统的文件下载方式通常是将整个文件读取到内存中,然后返回给客户端。这种方式在处理大文件时可能会导致内存占用过高。

2. 解决方案

  • 流式下载:通过流式处理避免将整个文件加载到内存中。
  • 支持断点续传:允许客户端从上次中断的位置继续下载。
流式下载

使用FileStreamResult实现流式下载:

代码语言:javascript
代码运行次数:0
运行
复制
[HttpGet("download/{fileName}")]
public IActionResult DownloadFile(string fileName)
{
    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "uploads", fileName);

    if (!System.IO.File.Exists(filePath))
        return NotFound("文件不存在");

    var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    return File(stream, "application/octet-stream", fileName);
}
支持断点续传

通过HTTP Range头实现断点续传:

代码语言:javascript
代码运行次数:0
运行
复制
[HttpGet("resume-download/{fileName}")]
public IActionResult ResumeDownload(string fileName)
{
    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "uploads", fileName);

    if (!System.IO.File.Exists(filePath))
        return NotFound("文件不存在");

    var fileSize = new FileInfo(filePath).Length;
    var rangeHeader = Request.Headers["Range"].ToString();

    if (!string.IsNullOrEmpty(rangeHeader))
    {
        var rangeValues = RangeHeaderValue.Parse(rangeHeader).Ranges.First();
        var start = rangeValues.From ?? 0;
        var length = rangeValues.To - start + 1;

        var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        stream.Seek(start, SeekOrigin.Begin);

        Response.Headers["Content-Range"] = $"bytes {start}-{rangeValues.To}/{fileSize}";
        Response.StatusCode = StatusCodes.Status206PartialContent;

        return File(stream, "application/octet-stream", fileName, false, (int)length);
    }

    return File(new FileStream(filePath, FileMode.Open, FileAccess.Read), "application/octet-stream", fileName);
}

总结

本文详细讲解了AspNetCore中文件上传和下载的优化方法,包括大文件上传、分块上传、断点续传以及高效的文件下载实现方式。这些技术不仅可以提升系统的性能,还能显著改善用户体验。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、大文件上传
    • 1. 传统方式的问题
    • 2. 解决方案
      • 调整请求大小限制
      • 流式上传
  • 二、分块上传
    • 1. 什么是分块上传?
    • 2. 实现步骤
      • 前端分块
      • 后端合并
  • 三、断点续传
    • 1. 什么是断点续传?
    • 2. 实现步骤
      • 记录上传进度
      • 恢复上传逻辑
  • 四、高效的文件下载
    • 1. 传统方式的问题
    • 2. 解决方案
      • 流式下载
      • 支持断点续传
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档