自学内容网 自学内容网

文件分片上传

分片上传:

1、前端(vue2+elementui)

<template>
  <div>
    <el-upload
      :http-request="handleUpload"
      :before-upload="beforeUpload"
      multiple
      :auto-upload="false"
      :on-change="handleFileChange"
    >
      <el-button slot="trigger" type="primary">选择文件</el-button>
      <el-button type="success" @click="submitUpload" :disabled="!file">上传</el-button>
    </el-upload>
    <el-progress v-if="progress > 0" :percentage="progress" status="success"></el-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      file: null, // 当前文件
      progress: 0, // 上传进度
      chunkSize: 5 * 1024 * 1024, // 每个分片大小 5MB
    };
  },
  methods: {
    // 文件选择回调
    handleFileChange(file) {
      this.file = file.raw;
    },

    // 上传前检查
    beforeUpload(file) {
      if (file.type !== "application/pdf") {
        this.$message.error("只能上传 PDF 文件!");
        return false;
      }
      if (file.size > 50 * 1024 * 1024) {
        this.$message.error("文件大小不能超过 50MB!");
        return false;
      }
      return true;
    },

    // 分片上传逻辑
    async handleUpload(option) {
      const file = option.file;
      const totalChunks = Math.ceil(file.size / this.chunkSize);
      let uploadedChunks = 0;

      for (let i = 0; i < totalChunks; i++) {
        const start = i * this.chunkSize;
        const end = Math.min(file.size, start + this.chunkSize);
        const chunk = file.slice(start, end);

        const formData = new FormData();
        formData.append("chunk", chunk);
        formData.append("fileName", file.name);
        formData.append("chunkIndex", i);
        formData.append("totalChunks", totalChunks);

        try {
          await this.$axios.post("/api/upload/chunk", formData);
          uploadedChunks++;
          this.progress = Math.round((uploadedChunks / totalChunks) * 100);
        } catch (error) {
          this.$message.error("上传失败,请重试!");
          console.error(error);
          return;
        }
      }

      // 通知服务器合并文件
      try {
        await this.$axios.post("/api/upload/merge", { fileName: file.name, totalChunks });
        this.$message.success("文件上传成功!");
      } catch (error) {
        this.$message.error("文件合并失败!");
        console.error(error);
      }
    },

    submitUpload() {
      if (this.file) {
        this.handleUpload({ file: this.file });
      } else {
        this.$message.error("请选择文件!");
      }
    },
  },
};
</script>

后端(.net6 webApi)

  1. 分片上传接口
    用于保存文件分片到临时目录:
[HttpPost("chunk")]
public async Task<IActionResult> UploadChunk([FromForm] IFormFile chunk, [FromForm] string fileName, [FromForm] int chunkIndex, [FromForm] int totalChunks)
{
    try
    {
        var tempFolder = Path.Combine("TempChunks", fileName);
        if (!Directory.Exists(tempFolder))
            Directory.CreateDirectory(tempFolder);

        var chunkPath = Path.Combine(tempFolder, $"{chunkIndex}");
        using (var stream = new FileStream(chunkPath, FileMode.Create))
        {
            await chunk.CopyToAsync(stream);
        }

        return Ok(new { success = true });
    }
    catch (Exception ex)
    {
        return BadRequest(new { success = false, message = ex.Message });
    }
}
  1. 文件合并接口
    用于将所有分片合并为一个完整文件:
[HttpPost("merge")]
public async Task<IActionResult> MergeFile([FromBody] MergeRequest mergeRequest)
{
    try
    {
        var tempFolder = Path.Combine("TempChunks", mergeRequest.FileName);
        if (!Directory.Exists(tempFolder))
            return BadRequest(new { success = false, message = "分片目录不存在" });

        var finalFolder = Path.Combine("Uploads");
        if (!Directory.Exists(finalFolder))
            Directory.CreateDirectory(finalFolder);

        var finalFilePath = Path.Combine(finalFolder, mergeRequest.FileName);
        using (var finalFileStream = new FileStream(finalFilePath, FileMode.Create))
        {
            for (int i = 0; i < mergeRequest.TotalChunks; i++)
            {
                var chunkPath = Path.Combine(tempFolder, $"{i}");
                if (!System.IO.File.Exists(chunkPath))
                    return BadRequest(new { success = false, message = $"缺少分片 {i}" });

                var chunkData = await System.IO.File.ReadAllBytesAsync(chunkPath);
                await finalFileStream.WriteAsync(chunkData, 0, chunkData.Length);

                System.IO.File.Delete(chunkPath); // 删除已合并的分片
            }
        }

        Directory.Delete(tempFolder); // 删除临时目录

        return Ok(new { success = true, path = $"/Uploads/{mergeRequest.FileName}" });
    }
    catch (Exception ex)
    {
        return BadRequest(new { success = false, message = ex.Message });
    }
}

public class MergeRequest
{
    public string FileName { get; set; }
    public int TotalChunks { get; set; }
}



原文地址:https://blog.csdn.net/qq_43893277/article/details/143986047

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!