上傳——斷點續傳之實踐篇(1)

在上一篇中,主要介紹了客戶端的斷點續傳的處理,這一篇,主要補充下服務端的斷點續傳。

服務端單線程斷點續傳

1、獲取上次傳輸的斷點

 var filePath = Path.Combine(rootFolderPath, document.WellId.ToString(), query.FileId + ".temp");
 if (System.IO.File.Exists(filePath))
 {
     var length = new FileInfo(filePath).Length;

     if (query.TotalSize > length)
     {
       response.Results = length;
     } 
  }

 

2、單線程寫入

 

 1        private WebApiResponse WriteToFile(string rootFilePath, Guid wellId, string fileId, string ext, IHttpFile file, bool isNotChunk, bool isLastChunk)
 2         {
 3             WebApiResponse response = new WebApiResponse();
 4 
 5             try
 6             {
 7                 var folderPath = Path.Combine(rootFilePath, wellId.ToString());
 8 
 9                 if (Directory.Exists(folderPath) == false)
10                 {
11                     Directory.CreateDirectory(folderPath);
12                 }
13                 if (isNotChunk)
14                 {
15                     var filePath = Path.Combine(folderPath, fileId + ext);
16 
17                     if (System.IO.File.Exists(filePath))
18                     {
19                         System.IO.File.Delete(filePath);
20                     }
21 
22                     using var stream = new FileStream(filePath, FileMode.CreateNew);
23                     file.InputStream.WriteTo(stream);
24 
25                 }
26                 else
27                 {
28                     //附加到臨時文件
29                     var filePath = Path.Combine(folderPath, fileId + ".temp");
30                     using var stream = new FileStream(filePath, FileMode.Append);
31                     file.InputStream.WriteTo(stream);
32                     stream?.Close();
33 
34                     if (isLastChunk)
35                     {
36                         //最後一個分片,更新文件名
37 
38                         var tempFilePath = Path.Combine(folderPath, fileId + ".temp");
39 
40                         var targetFilePath = Path.Combine(folderPath, fileId + ext);
41 
42                         System.IO.File.Move(tempFilePath, targetFilePath, true);
43                     }
44                 }
45             }
46             catch (Exception ex)
47             {
48                 return WebApiResponse.Fail("文件上傳中出錯:" + ex.Message);
49             }
50 
51             return response;
52         }

 

服務端多線程斷點續傳

1、獲取上次已經上傳的分片

  

 1                   //獲取臨時文件夾中文件數,減去1,防止分片不完整
 2                     var mergeDirPath = Path.Combine(rootFolderPath, document.WellId.ToString(), "Temp");
 3 
 4                     if (Directory.Exists(mergeDirPath))
 5                     {
 6                         DirectoryInfo di = new DirectoryInfo(mergeDirPath);
 7 
 8                         //刪除掉一些fileId對應不上的文件
 9 
10                         var tempfiles = di.GetFiles();
11 
12                         for (int i = 0; i < tempfiles.Length; i++)
13                         {
14                             if (!tempfiles[i].Name.Contains(query.FileId))
15                             {
16                                 tempfiles[i].Delete();
17                             }
18                         }
19 
20                         var files = di.GetFiles().OrderBy(f => f.CreationTime).ToList();
21 
22                         List<int> seqs = new List<int>();
23 
24                         foreach (var item in files)
25                         {
26                             //去掉小於片區的文件
27                             if (item.Length != query.ChunkSize) continue;
28                             var pName = Path.GetFileNameWithoutExtension(item.Name);
29 
30                             var s = pName.Last().ToString();
31 
32                             seqs.Add(int.Parse(s));
33                         }
34 
35                         response.Results = seqs;
36                     }

 

2、多線程寫入

 1        private WebApiResponse MulThreadWriteToFile(string rootFilePath, Guid wellId, string fileId, IHttpFile file, long chunkNumber)
 2         {
 3             WebApiResponse response = new WebApiResponse();
 4 
 5             try
 6             {
 7                 var folderPath = Path.Combine(rootFilePath, wellId.ToString(), "Temp");
 8 
 9                 if (Directory.Exists(folderPath) == false)
10                 {
11                     Directory.CreateDirectory(folderPath);
12                 }
13 
14                 var filePath = Path.Combine(folderPath, fileId + chunkNumber + ".temp");
15 
16                 if (System.IO.File.Exists(filePath))
17                 {
18                     System.IO.File.Delete(filePath);
19                 }
20 
21                 using var stream = new FileStream(filePath, FileMode.CreateNew);
22                 file.InputStream.WriteTo(stream);
23                 stream?.Close();
24             }
25             catch (Exception ex)
26             {
27                 WebApiResponse.Fail("文件上傳中出錯:" + ex.Message);
28             }
29 
30             return response;
31         }

 

3、多線程完成後通知

 DirectoryInfo di = new DirectoryInfo(mergeDirPath);
 var files = di.GetFiles().OrderBy(f => f.Name).ToList();

  foreach (var item in files)
  {
        using var stream = new FileStream(filePath, FileMode.Append);

        using var fs = item.OpenRead();

        fs.WriteTo(stream);

        fs?.Close();

        stream?.Close();
  }

 

客戶端多線程上傳

NeedAddFiles爲要上傳的文件集合,按分頁的思想,每一頁的列表上傳,分給一個task,頁內是一個一個文件上傳的,多頁是併發上傳的。

                    while (true)
                    {
                        var sources = NeedAddFiles.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                        if (sources.Count == 0) break;

                        pageIndex++;

                        var task = Task.Run(function: async () =>
                        {
                            foreach (var item in sources)
                            {
                                await FileUpload(item.Key, item.Value);
                                await Task.Delay(5);
                            }
                        });

                        tasks.Add(task);
                    }

                    //等待所有線程完成
                    await Task.WhenAll(tasks).ContinueWith(t =>
                    {
                        Console.WriteLine("多線程上傳任務已完成");
                    });

                    Console.WriteLine("等待線程已完成");

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章