侧边栏壁纸
博主头像
小医仙博主等级

风一程雨一程,身向榆关那畔行。

  • 累计撰写 39 篇文章
  • 累计创建 16 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

.Net Core 文件切片上传

小医仙
2023-06-13 / 0 评论 / 0 点赞 / 241 阅读 / 624 字

前端代码

<html>
  <head> </head>
  <body>
    <input id="fileInput" type="file" />

    <button id="uploadBtn">上传</button>

    <div id="progressBar"></div>

    <script>
      async function handleUpload() {
        const fileInput = document.getElementById("fileInput");
        const progressBar = document.getElementById("progressBar");
        const uploadBtn = document.getElementById("uploadBtn");

        // Disable upload button to prevent multiple uploads
        uploadBtn.disabled = true;

        const file = fileInput.files[0];
        if (!file) {
          alert("请选择要上传的文件");
          return;
        }

        // Determine chunk size
        const chunkSize = 1024 * 1024; // 1MB (可根据实际需求调整)

        // Determine total number of chunks
        const numChunks = Math.ceil(file.size / chunkSize);

        // Initialize state
        let start = 0;
        let end = 0;
        let currentChunk = 1;
        let progress = 0;
        let uploadId = "";

        // Loop through chunks and upload them one at a time
        while (end < file.size) {
          end = Math.min(start + chunkSize, file.size);

          // Create new FormData object and append current chunk to it
          const formData = new FormData();
          formData.append("chunk", file.slice(start, end));

          // Append state to FormData object
          formData.append("currentChunk", currentChunk);
          formData.append("numChunks", numChunks);
          formData.append("fileName", file.name);
          formData.append("fileSize", file.size);
          formData.append("uploadId", uploadId);

          // Send POST request to server
          const result = await fetch("http://10.0.0.6:44368/api/upload", {
            method: "POST",
            body: formData,
          });

          // Handle response from server
          const json = await result.json();
          progress = (currentChunk / numChunks) * 100;
          progressBar.style.width = `${progress}%`;
          if (json.uploadId) {
            uploadId = json.uploadId;
          }

          // Update state
          currentChunk++;
          start = end;
        }

        // Reset progress bar
        progressBar.style.width = "0%";
        alert("上传完成!");

        // Enable upload button
        uploadBtn.disabled = false;
      }

      const uploadBtn = document.getElementById("uploadBtn");
      uploadBtn.addEventListener("click", handleUpload);
    </script>
  </body>
</html>

服务端代码

 [HttpPost("api/upload")]
    public async Task<IActionResult> Upload()
    {
        var uploadDirectory = Path.Combine("UploadDirectory");
        try
        {
            // 从请求中读取表单数据
            var form = await Request.ReadFormAsync();
            var chunk = form.Files.GetFile("chunk");
            var currentChunk = int.Parse(form["currentChunk"]);
            var numChunks = int.Parse(form["numChunks"]);
            var fileName = form["fileName"];
            var fileSize = long.Parse(form["fileSize"]);
            var uploadId = form["uploadId"];

            // 如果未指定uploadId,则生成一个新的
            if (string.IsNullOrEmpty(uploadId))
            {
                uploadId = Guid.NewGuid().ToString();
            }

            // 确定块目录和文件路径
            var chunkDirectory = Path.Combine(uploadDirectory, uploadId);
            var chunkPath = Path.Combine(chunkDirectory, $"{currentChunk}.dat");

            // 如果块目录不存在,则创建块目录
            Directory.CreateDirectory(chunkDirectory);

            // 保存数据块到硬盘
            await using var fileStream = new FileStream(chunkPath, FileMode.Create, FileAccess.Write);
            await chunk?.CopyToAsync(fileStream)!;
            fileStream.Close();
            // 如果这是最后一个块 则合并所有的块
            if (currentChunk == numChunks)
            {
                var filePath = Path.Combine(uploadDirectory, fileName);
                await using var mergedFileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
                for (var i = 1; i <= numChunks; i++)
                {
                    var chunkFilePath = Path.Combine(chunkDirectory, $"{i}.dat");

                    // 切片文件 n IN 1
                    await using var chunkStream = new FileStream(chunkFilePath, FileMode.Open, FileAccess.Read);
                    await chunkStream.CopyToAsync(mergedFileStream);
                }

                mergedFileStream.Close();
                // 删除块目录
                Directory.Delete(chunkDirectory, true);
            }

            // 将上传的标识信息返回给客户端
            var result = new { uploadId };
            return Ok(result);
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }

评论区