一、引言
在Web應用中,檔案上傳是一個常見的功能。然而,當處理大檔案上傳時,傳統的上傳方式可能會遇到效能瓶頸、超時或記憶體溢位等問題。為了解決這個問題,我們可以採用分塊上傳的方式,將大檔案切分成多個小塊,然後逐個上傳。這種方式不僅可以提高上傳的成功率,還可以提供更好的使用者體驗。
二、大檔案上傳原理
大檔案上傳的核心原理是將檔案切分成多個小塊(chunks),然後逐個上傳這些小塊。每個小塊上傳完成後,伺服器會返回一個確認資訊,表示該小塊已成功接收。客戶端在收到確認資訊後,再繼續上傳下一個小塊。這種方式的好處是可以有效避免網路中斷或伺服器超時導致的上傳失敗,同時減輕伺服器的記憶體壓力。
三、C#實現方案
以下是一個簡單的C#實現方案,用於處理大檔案的分塊上傳。
- 客戶端實現
客戶端需要將大檔案切分成多個小塊,並逐個上傳。以下是一個簡單的C#示例,展示如何將檔案切分成小塊並上傳:
1 using System; 2 using System.IO; 3 using System.Net.Http; 4 using System.Threading.Tasks; 5 6 public class FileUploader 7 { 8 private const int ChunkSize = 1024 * 1024; // 1MB 9 private readonly HttpClient _httpClient; 10 private readonly string _uploadUrl; 11 12 public FileUploader(HttpClient httpClient, string uploadUrl) 13 { 14 _httpClient = httpClient; 15 _uploadUrl = uploadUrl; 16 } 17 18 public async Task UploadFileAsync(string filePath) 19 { 20 using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 21 { 22 long fileLength = fileStream.Length; 23 int chunkCount = (int)Math.Ceiling((double)fileLength / ChunkSize); 24 25 for (int i = 0; i < chunkCount; i++) 26 { 27 long offset = i * ChunkSize; 28 byte[] buffer = new byte[ChunkSize]; 29 int bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length); 30 if (bytesRead < buffer.Length) 31 { 32 Array.Resize(ref buffer, bytesRead); 33 } 34 35 using (var content = new ByteArrayContent(buffer)) 36 { 37 HttpResponseMessage response = await _httpClient.PostAsync($"{_uploadUrl}?chunkIndex={i}", content); 38 response.EnsureSuccessStatusCode(); 39 } 40 } 41 } 42 } 43 }
在這個示例中,我們定義了一個FileUploader
類,它接受一個HttpClient
例項和一個上傳URL。UploadFileAsync
方法接受一個檔案路徑,將檔案切分成多個1MB的小塊,並逐個上傳。注意,在實際應用中,你可能需要新增更多的錯誤處理和重試邏輯。
- 伺服器端實現
伺服器端需要接收並處理客戶端上傳的檔案塊。以下是一個簡單的ASP.NET Core Web API示例,用於接收並儲存上傳的檔案塊:
1 using Microsoft.AspNetCore.Http; 2 using Microsoft.AspNetCore.Mvc; 3 using System.IO; 4 using System.Threading.Tasks; 5 6 [ApiController] 7 [Route("[controller]")] 8 public class FileUploadController : ControllerBase 9 { 10 [HttpPost] 11 public async Task<IActionResult> UploadFile(IFormFile file, int chunkIndex) 12 { 13 string filePath = Path.Combine(Directory.GetCurrentDirectory(), $"temp_file_{chunkIndex}.dat"); 14 using (var stream = new FileStream(filePath, FileMode.Create)) 15 { 16 await file.CopyToAsync(stream); 17 } 18 return Ok(); 19 } 20 }
在這個示例中,我們定義了一個FileUploadController
類,它有一個UploadFile
方法用於接收上傳的檔案塊。這個方法將每個檔案塊儲存為一個臨時檔案。在實際應用中,你可能需要將這些檔案塊合併成一個完整的檔案,並進行相應的處理。
四、結論
大檔案上傳是一個常見的需求,但透過分塊上傳的方式,我們可以有效地解決這個問題。在C#中,我們可以利用HttpClient
和ASP.NET Core Web API來實現客戶端和伺服器端的分塊上傳功能。透過切分檔案並逐個上傳小塊,我們可以提高上傳的成功率,並提供更好的使用者體驗。同時,在伺服器端,我們需要相應地處理這些檔案塊,並最終將它們合併成一個完整的檔案。