2011-11-09 66 views
1

我發現在計算器下面的代碼resumeable文件下載:resumeable文件下載的問題 - >當文件大小比Int32.MaxValue(2GB)以上(大文件)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Text; 
using System.IO; 
using System.Threading; 
using System.Security.Cryptography; 
using System.Net; 

namespace WindowsServer.Classes 
{ 
    public class DownloadFile 
    { 

     public static bool DownloadFileMethod_2(HttpContext httpContext, string filePath, long speed) 
     { 
      // Many changes: mostly declare variables near use 
      // Extracted duplicate references to HttpContext.Response and .Request 
      // also duplicate reference to .HttpMethod 

      // Removed try/catch blocks which hid any problems 
      var response = httpContext.Response; 
      var request = httpContext.Request; 
      var method = request.HttpMethod.ToUpper(); 
      if (method != "GET" && 
       method != "HEAD") 
      { 
       response.StatusCode = 501; 
       return false; 
      } 

      if (!File.Exists(filePath)) 
      { 
       response.StatusCode = 404; 
       return false; 
      } 

      // Stream implements IDisposable so should be in a using block 
      using (var myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
      { 
       var fileLength = myFile.Length; 
       if (fileLength > Int32.MaxValue) 
       { 
        response.StatusCode = 413; 
        return false; 
       } 

       var lastUpdateTiemStr = File.GetLastWriteTimeUtc(filePath).ToString("r"); 
       var fileName = Path.GetFileName(filePath); 
       var fileNameUrlEncoded = HttpUtility.UrlEncode(fileName, Encoding.UTF8); 
       var eTag = fileNameUrlEncoded + lastUpdateTiemStr; 

       var ifRange = request.Headers["If-Range"]; 
       if (ifRange != null && ifRange.Replace("\"", "") != eTag) 
       { 
        response.StatusCode = 412; 
        return false; 
       } 

       long startBytes = 0; 

       // Just guessing, but I bet you want startBytes calculated before 
       // using to calculate content-length 
       var rangeHeader = request.Headers["Range"]; 
       if (rangeHeader != null) 
       { 
        response.StatusCode = 206; 
        var range = rangeHeader.Split(new[] { '=', '-' }); 
        startBytes = Convert.ToInt64(range[1]); 
        if (startBytes < 0 || startBytes >= fileLength) 
        { 
         // TODO: Find correct status code 
         response.StatusCode = (int)HttpStatusCode.BadRequest; 
         response.StatusDescription = 
          string.Format("Invalid start of range: {0}", startBytes); 
         return false; 
        } 
       } 

       response.Clear(); 
       response.Buffer = false; 
       response.AddHeader("Content-MD5", GetMD5Hash_2(filePath)); 
       response.AddHeader("Accept-Ranges", "bytes"); 
       response.AppendHeader("ETag", string.Format("\"{0}\"", eTag)); 
       response.AppendHeader("Last-Modified", lastUpdateTiemStr); 
       response.ContentType = "application/octet-stream"; 
       response.AddHeader("Content-Disposition", "attachment;filename=" + 
                  fileNameUrlEncoded.Replace("+", "%20")); 
       var remaining = fileLength - startBytes; 
       response.AddHeader("Content-Length", remaining.ToString()); 
       response.AddHeader("Connection", "Keep-Alive"); 
       response.ContentEncoding = Encoding.UTF8; 

       if (startBytes > 0) 
       { 
        response.AddHeader("Content-Range", 
             string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength)); 
       } 

       // BinaryReader implements IDisposable so should be in a using block 
       using (var br = new BinaryReader(myFile)) 
       { 
        br.BaseStream.Seek(startBytes, SeekOrigin.Begin); 

        const int packSize = 1024 * 10; //read in block,every block 10K bytes 
        var maxCount = (int)Math.Ceiling((remaining + 0.0)/packSize); //download in block 
        for (var i = 0; i < maxCount && response.IsClientConnected; i++) 
        { 
         response.BinaryWrite(br.ReadBytes(packSize)); 
         response.Flush(); 

         // HACK: Unexplained sleep 
         var sleep = (int)Math.Ceiling(1000.0 * packSize/speed); //the number of millisecond 
         if (sleep > 1) Thread.Sleep(sleep); 
        } 
       } 
      } 
      return true; 
     } 

     static string GetMD5Hash_2(string input) 
     { 
      // Create a new instance of the MD5CryptoServiceProvider object. 
      MD5 md5Hasher = MD5.Create(); 

      // Convert the input string to a byte array and compute the hash. 
      byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input)); 

      // Create a new Stringbuilder to collect the bytes 
      // and create a string. 
      StringBuilder sBuilder = new StringBuilder(); 

      // Loop through each byte of the hashed data 
      // and format each one as a hexadecimal string. 
      for (int i = 0; i < data.Length; i++) 
      { 
       sBuilder.Append(data[i].ToString("x2")); 
      } 

      // Return the hexadecimal string. 
      return sBuilder.ToString(); 
     } 

    } 
} 

此方法將返回false時文件大小比Int32.MaxValue大!
我們如何才能更改此方法的大文件,如10GB或更多?

+0

似乎那個傢伙因爲這個問題而被摧毀......(可憐的傢伙)(對他來說太難過了!)/但親愛的朋友們,我們在這裏學習,而不是一起爲了一個問題而壓低和禁止! – MoonLight

回答

5

因爲代碼包含return false,如果文件大小比Int32.MaxValue更大返回false:

var fileLength = myFile.Length; 
     if (fileLength > Int32.MaxValue) 
     { 
      response.StatusCode = 413; 
      return false; 
     } 

是否回答你的問題,或者你想知道爲什麼添加原代碼那條款?如果你不明白爲什麼,你確定要使用intertubez上的這個隨機代碼嗎?

+0

簡單的調試也會發現這個問題。 – McKay

+2

爲什麼不使用你不明白的代碼的完美例子。 –

+0

嗨,謝謝你的回答!我瞭解這些代碼,我知道這種情況永遠不會是真的!但我想向專業人士展示該方法,以獲取大於2 GB的下載文件的最佳方法! (平均版本和自定義) – MoonLight

1
var fileLength = myFile.Length; 

我很遺憾var在這裏使用。 fileLengthlong,那就足夠了。

if (fileLength > Int32.MaxValue) 
    { 
     response.StatusCode = 413; 
     return false; 
    } 

似乎沒有必要。

+0

'var'方面與它有什麼關係? – Gabe

+2

@gabe不是每個人都知道Stream.Length是一個很長的。我絕不會在這裏使用'var'。 –

+0

我不知道這是'long',但如果它是'int','fileLength> Int32.MaxValue'永遠不會是真的。 – Gabe