欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# FileStream實現(xiàn)多線程斷點續(xù)傳

 更新時間:2018年03月22日 11:28:58   作者:airforce094  
這篇文章主要為大家詳細介紹了C# FileStream實現(xiàn)多線程斷點續(xù)傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下

一、前言

       網(wǎng)上有許多的多線程斷點續(xù)傳操作,但總是寫的很云里霧里,或者寫的比較坑長。由于這幾個月要負責公司的在線升級項目,所以正好順便寫了一下

代碼如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace TestCenter
{
 class Program
 {
  static void Main(string[] args)
  {
   string LocalSavePath = @"E:\Test\TestFile\Local\1.msi"; //本地目標文件路徑

   FileInfo SeverFilePath = new FileInfo(@"E:\Test\TestFile\Server\1.msi"); //服務(wù)器待文件路徑
   long FileLength = SeverFilePath.Length; //待下載文件大小


   Console.WriteLine("Start Configuration");
   int PackCount = 0; //初始化數(shù)據(jù)包個數(shù)

   long PackSize = 1024000; //數(shù)據(jù)包大小

   if (FileLength % PackSize > 0)
   {
    PackCount = (int)(FileLength / PackSize) + 1;
   }

   else
   {
    PackCount = (int)(FileLength / PackSize);
   }


   Console.WriteLine("Start Recieve");
   var tasks = new Task[PackCount]; //多線程任務(wù)

   for (int index = 0; index < PackCount; index++)
   {


    int Threadindex = index; //這步很關(guān)鍵,在Task()里的絕對不能直接使用index
    var task = new Task(() =>
    {
     string tempfilepath = @"E:\Test\TestFile\Temp\" + "QS_" + Threadindex + "_" + PackCount; //臨時文件路徑

     using (FileStream tempstream = new FileStream(tempfilepath, FileMode.Create, FileAccess.Write, FileShare.Write))
     {
      int length = (int)Math.Min(PackSize, FileLength - Threadindex * PackSize);

      var bytes = GetFile(Threadindex*PackCount, length);

      tempstream.Write(bytes, 0, length);
      tempstream.Flush();
      tempstream.Close();
      tempstream.Dispose();
     }
    });
    tasks[Threadindex] = task;
    task.Start();
   }

   Task.WaitAll(tasks); //等待所有線程完成
   Console.WriteLine("Recieve End");


   //檢測有哪些數(shù)據(jù)包未下載
   Console.WriteLine("Start Compare");
   DirectoryInfo TempDir = new DirectoryInfo(@"E:\Test\TestFile\temp"); //臨時文件夾路徑
   List<string> Comparefiles = new List<string>();

   for (int i = 0; i < PackCount; i++)
   {
    bool hasfile = false;
    foreach (FileInfo Tempfile in TempDir.GetFiles())
    {
     if (Tempfile.Name.Split('_')[1] == i.ToString())
     {
      hasfile = true;
      break;
     }
    }
    if (hasfile == false)
    {
     Comparefiles.Add(i.ToString());
    }
   }

   //最后補上這些缺失的文件
   if (Comparefiles.Count > 0)
   {
    foreach (string com_index in Comparefiles)
    {
     string tempfilepath = @"E:\Test\TestFile\Temp\" + "QS_" + com_index+ "_" + PackCount;
     using (FileStream Compstream = new FileStream(tempfilepath, FileMode.Create, FileAccess.Write, FileShare.Write))
     {
      int length = (int)Math.Min(PackSize, FileLength - Convert.ToInt32(com_index) * PackSize);
      var bytes = GetFile(Convert.ToInt32(com_index)*PackCount, length);
      Compstream.Write(bytes, 0, length);
      Compstream.Flush();
      Compstream.Close();
      Compstream.Dispose();
     }
    }

   }
   Console.WriteLine("Compare End");


   //準備將臨時文件融合并寫到1.msi中
   Console.WriteLine("Start Write");
   using (FileStream writestream = new FileStream(LocalSavePath, FileMode.Create, FileAccess.Write, FileShare.Write))
   {
    foreach (FileInfo Tempfile in TempDir.GetFiles())
    {
     using (FileStream readTempStream = new FileStream(Tempfile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
     {
      long onefileLength = Tempfile.Length;
      byte[] buffer = new byte[Convert.ToInt32(onefileLength)];
      readTempStream.Read(buffer, 0, Convert.ToInt32(onefileLength));
      writestream.Write(buffer, 0, Convert.ToInt32(onefileLength));
     }
    }
    writestream.Flush();
    writestream.Close();
    writestream.Dispose();
   }
   Console.WriteLine("Write End");



   //刪除臨時文件
   Console.WriteLine("Start Delete Temp Files");
   foreach (FileInfo Tempfile in TempDir.GetFiles())
   {
    Tempfile.Delete();
   }
   Console.WriteLine("Delete Success");
   Console.ReadKey();
  }


  //這個方法可以放到Remoting或者WCF服務(wù)中去,然后本地調(diào)用該方法即可實現(xiàn)多線程斷點續(xù)傳
  public static byte[] GetFile(int start, int length)
  {
   string SeverFilePath = @"E:\Test\TestFile\Server\1.msi";
   using (FileStream ServerStream = new FileStream(SeverFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024*80, true))
   {
    byte[] buffer = new byte[length];
    ServerStream.Position = start;
    //ServerStream.Seek(start, SeekOrigin.Begin);
    ServerStream.Read(buffer, 0, length);
    return buffer;
   }
  }
 }
}

二、討論     

1)需要注意的是第44行,不能直接使用index變量在Task()里進行操作,而是要將它賦給Threadindex,讓Threadindex在Task()里,不然會直接報錯,為什么呢?查看鏈接

2)70至108行代碼可以在外面再套一層while循環(huán),循環(huán)檢測臨時文件是否下完整了,然后再定義一個檢測最大上限,超過這個上限就放棄本次更新,當用戶的網(wǎng)絡(luò)恢復(fù)正常后下次再做更新操作。所以說放臨時文件的文件夾最好要包含版本信息,不會把2.0.0的臨時文件和1.0.0的臨時文件搞混。

3) FileStream.Position 與 FileStream.Seek(long offset, SeekOrigin seekorigin) 的作用都是獲取流的指針位置,當文件路徑使用絕對路徑時使用Position;相對路徑時使用Seek方法,查看鏈接

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論