PDA

View Full Version : نحوه file resume during download در .net و c#



majid_darab
دوشنبه 09 آبان 1390, 03:50 صبح
با سلام و عرض خسته نباشید خدمت دوستان عزیز :
من از handler زیر برای دانلود فایل استفاده می کنم.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;

namespace NiceFileExplorer
{
/// <summary>
/// Summary description for HandlerForMyFE
/// </summary>
public class HandlerForMyFE : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{

private HttpContext _context;
private HttpContext Context
{
get
{
return _context;
}
set
{
_context = value;
}
}

public void ProcessRequest(HttpContext context)
{
Context = context;
string filePath = context.Request.QueryString["Downloadpath"];
filePath = context.Server.MapPath(filePath);

if (filePath == null)
{
return;
}

System.IO.StreamReader streamReader = new System.IO.StreamReader(filePath);
System.IO.BinaryReader br = new System.IO.BinaryReader(streamReader.BaseStream);

byte[] bytes = new byte[streamReader.BaseStream.Length];

br.Read(bytes, 0, (int)streamReader.BaseStream.Length);

if (bytes == null)
{
return;
}

streamReader.Close();
br.Close();
string fileName = System.IO.Path.GetFileName(filePath);
string MimeType = GetMimeType(fileName);
string extension = System.IO.Path.GetExtension(filePath);
char[] extension_ar = extension.ToCharArray();
string extension_Without_dot = string.Empty;
for (int i = 1; i < extension_ar.Length; i++)
{
extension_Without_dot += extension_ar[i];
}

string filesize = string.Empty;
FileInfo f = new FileInfo(filePath);
filesize = f.Length.ToString();

//if (extension == ".jpg")
//{ // Handle *.jpg and
// WriteFile(bytes, fileName, "image/jpeg jpeg jpg jpe", context.Response);
//}
//else if (extension == ".gif")
//{// Handle *.gif
// WriteFile(bytes, fileName, "image/gif gif", context.Response);
//}

WriteFile(bytes, fileName, filesize, MimeType + " " + extension_Without_dot, context.Response);

////context = HttpContext
//context.Response.Clear();
//context.Response.ContentType = MimeType;
//context.Response.TransmitFile(filePath);
//context.Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
//FileInfo f = new FileInfo(filePath);
//context.Response.AddHeader("Content-Length", f.Length.ToString());
//context.Response.Flush();
//context.Response.End();
}

private void WriteFile(byte[] content, string fileName, string filesize, string contentType, HttpResponse response)
{
response.Buffer = true;
response.Clear();

response.ContentType = contentType;

response.AddHeader("content-disposition", "attachment; filename=" + fileName);

response.AddHeader("Content-Length", filesize);

response.BinaryWrite(content);
response.Flush();
response.End();
}

private string GetMimeType(string fileName)
{
string mimeType = "application/unknown";
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ex t);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}

public bool IsReusable
{
get
{
return false;
}
}
}
}
نحوه کار این handler این است که از query string با نام path آدرس فایل مورد نظرو دریافت و سپس اونو برای دانلود آماده می کند و پنجره دانلود در بروزر ظاهر می گردد.
زمانی که با دانلود منیجر اقدام به دانلود فایل می کنیم می بینیم که فایل مورد نظر قابل resume نیست!
چطور می شود دانلود فایل مورد نظر را resume able کرد؟

با تشکر از حسن توجه شما

aminghaderi
دوشنبه 09 آبان 1390, 07:49 صبح
سلام .
به موضوعی بسیار خوب و مهمی اشاره کردی که خود من هم بهش نیاز دارم ، خوب با توجه به جستجویی که من انجام دادم ،خیلی هم منبع در این باره وجود نداره؟!
حدودا یک ساعت و نیم وقت گذاشتم تا تونستم لینک های زیر رو از بین حدودا 100 لینک مورد جستجو گزینش کنم و اینجا برای شما و دوستان قرار بدهم ؟!:کف:
خوب از این قسمت به بعد با شما ، فقط لطف کنید ، در صورتی که موفق شدی ، نمونه کد به نتیجه رسیده رو اینجا قرار بدهید تا همه از اون استفاده کنیم تا کسی مجدد این وقت رو از دست ندهد؟!

http://www.abhisheksur.com/2010/09/progress-streamed-file-download-and.html
http://forums.asp.net/p/1568568/3924759.aspx
http://forums.asp.net/t/1218116.aspx
http://www.devx.com/dotnet/Article/22533/0/page/2


موفق باشی.

majid_darab
دوشنبه 09 آبان 1390, 10:58 صبح
با تشکر از پاسخ شما ...
من واقعاً بابت این قضیه در دات نت در تعجبم!
ظاهر امر اینجوریه که در php با یک حرکت قضیه ok می شود ، اما معلوم نیست چرا در دات نت زیاد به این موضوع پرداخته نشده است.
انگار داری راجع به موضوع جیز تحقیق می کنی و آدم بیشتر کنجکاو میشه دنبال جواب مساله بگرده ...
به غیر از یک فروم asp.net مرجع کاملی راجع به این موضوع پیدا نکردم و از بابت لینک های اعلام شده تشکر می کنم.
وقتی از یکی از expert های مایکروسافت درخواست کردم که کلاس کامل قضیه رو که فایل های با حجم بالا را هم ساپورت کنه معرفی نماید با پاسخ غیر منطقی زیر روبرو شدم :
(باید برای این قضیه platform نوشته شود که زمان زیادی به طول خواهد انجامید و یک سری داستان راجع به platform تعریف کرد که گویی قرار بود از موضوع اصلی منحرف شویم)

majid_darab
دوشنبه 09 آبان 1390, 11:06 صبح
لذا کلاس زیر کار رو راه می اندازد که از مدیران محترم تقاضامند موشکافی و تصحیح و بررسی آن هستم :
(تنها مشکلی که در موقع کار دیدم این بود که وقتی با internet download manager اقدام به دانلود می کنید گزینه resume به صورت unknown نشان داده می شود و این در حالی ست که که همه چی به خوبی کار می کند)
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;

namespace NiceFileExplorer.Classes
{
public class DownloadFile
{
public static bool DownloadFileMethod(HttpContext httpContext, string filePath, long speed)
{
bool ret = true;
try
{
switch (httpContext.Request.HttpMethod.ToUpper())
{ //support Get and head method
case "GET":
case "HEAD":
break;
default:
httpContext.Response.StatusCode = 501;
return false;
}
if (!File.Exists(filePath))
{
httpContext.Response.StatusCode = 404;
return false;
}
//#endregion

var fileInfo = new FileInfo(filePath);

long startBytes = 0;
int packSize = 1024 * 10; //read in block,every block 10K bytes
string fileName = Path.GetFileName(filePath);
FileStream myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
long fileLength = myFile.Length;

int sleep = (int)Math.Ceiling(1000.0 * packSize / speed);//the number of millisecond
string lastUpdateTiemStr = File.GetLastWriteTimeUtc(filePath).ToString("r");
string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + lastUpdateTiemStr;

//validate whether the file is too large
if (myFile.Length > Int32.MaxValue)
{
httpContext.Response.StatusCode = 413;
return false;
}

if (httpContext.Request.Headers["If-Range"] != null)
{

if (httpContext.Request.Headers["If-Range"].Replace("\"", "") != eTag)
{
httpContext.Response.StatusCode = 412;
return false;
}
}
//#endregion

try
{

httpContext.Response.Clear();
httpContext.Response.Buffer = false;
httpContext.Response.AddHeader("Content-MD5", GetMD5Hash(fileInfo));
httpContext.Response.AddHeader("Accept-Ranges", "bytes");
httpContext.Response.AppendHeader("ETag", "\"" + eTag + "\"");
httpContext.Response.AppendHeader("Last-Modified", lastUpdateTiemStr);
httpContext.Response.ContentType = "application/octet-stream";
httpContext.Response.AddHeader("Content-Disposition", "attachment;filename=" +

HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", "%20"));
httpContext.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
httpContext.Response.AddHeader("Connection", "Keep-Alive");
httpContext.Response.ContentEncoding = Encoding.UTF8;
if (httpContext.Request.Headers["Range"] != null)
{
httpContext.Response.StatusCode = 206;
string[] range = httpContext.Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[1]);
if (startBytes < 0 || startBytes >= fileLength)
{
return false;
}
}
if (startBytes > 0)
{
httpContext.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
//#endregion

//send data
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Ceiling((fileLength - startBytes + 0.0) / packSize);//download in block
for (int i = 0; i < maxCount && httpContext.Response.IsClientConnected; i++)
{
httpContext.Response.BinaryWrite(br.ReadBytes(pack Size));
httpContext.Response.Flush();
if (sleep > 1) Thread.Sleep(sleep);
}
//#endregion
}
catch
{
ret = false;
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
ret = false;
}
return ret;
}

private static string GetMD5Hash(FileInfo file)
{
var stream = file.OpenRead();
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(stream);
stream.Close();

var sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}


//static string GetMD5Hash(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(in put));

// // 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();
//}


}
}

شاد و سربلند باشید