see the below handler :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FileExplorer
{
/// <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];
}
//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);
//}
if (HttpContext.Current.Session["User_ID"] != null)
{
WriteFile(bytes, fileName, MimeType + " " + extension_Without_dot, context.Response);
}
}
private void WriteFile(byte[] content, string fileName, string contentType, HttpResponse response)
{
response.Buffer = true;
response.Clear();
response.ContentType = contentType;
response.AddHeader("content-disposition", "attachment; filename=" + fileName);
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(ext);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
i use this handler for downloading my files without opening them directly in browser -> (using query string path)
how can i make my files resumeable ?
i don't have that option in internet download manager!
As requested, here's a "cleaned up" version of the answer:
public static bool DownloadFileMethod(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(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;
}
here is the answer!
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(packSize));
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();
}
}
}
And here's the official implementation provided by MSDN:
http://code.msdn.microsoft.com/Implement-resume-in-aspnet-c1bbde36/view/SourceCode
Downloader.cs
using System;
using System.IO;
using System.Text;
using System.Web;
namespace CSASPNETResumeDownload
{
public class Downloader
{
public static void DownloadFile(HttpContext httpContext, string filePath)
{
if (!IsFileExists(filePath))
{
httpContext.Response.StatusCode = 404;
return;
}
FileInfo fileInfo = new FileInfo(filePath);
if (fileInfo.Length > Int32.MaxValue)
{
httpContext.Response.StatusCode = 413;
return;
}
// Get the response header information by the http request.
HttpResponseHeader responseHeader = GetResponseHeader(httpContext.Request, fileInfo);
if (responseHeader == null)
{
return;
}
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
try
{
SendDownloadFile(httpContext.Response, responseHeader, fileStream);
}
catch (HttpException ex)
{
httpContext.Response.StatusCode = ex.GetHttpCode();
}
finally
{
fileStream.Close();
}
}
/// <summary>
/// Check whether the file exists.
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private static bool IsFileExists(string filePath)
{
bool fileExists = false;
if (!string.IsNullOrEmpty(filePath))
{
if (File.Exists(filePath))
{
fileExists = true;
}
}
return fileExists;
}
/// <summary>
/// Get the response header by the http request.
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="fileInfo"></param>
/// <returns></returns>
private static HttpResponseHeader GetResponseHeader(HttpRequest httpRequest, FileInfo fileInfo)
{
if (httpRequest == null)
{
return null;
}
if (fileInfo == null)
{
return null;
}
long startPosition = 0;
string contentRange = "";
string fileName = fileInfo.Name;
long fileLength = fileInfo.Length;
string lastUpdateTimeStr = fileInfo.LastWriteTimeUtc.ToString();
string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + " " + lastUpdateTimeStr;
string contentDisposition = "attachment;filename=" + HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", "%20");
if (httpRequest.Headers["Range"] != null)
{
string[] range = httpRequest.Headers["Range"].Split(new char[] { '=', '-' });
startPosition = Convert.ToInt64(range[1]);
if (startPosition < 0 || startPosition >= fileLength)
{
return null;
}
}
if (httpRequest.Headers["If-Range"] != null)
{
if (httpRequest.Headers["If-Range"].Replace("\"", "") != eTag)
{
startPosition = 0;
}
}
string contentLength = (fileLength - startPosition).ToString();
if (startPosition > 0)
{
contentRange = string.Format(" bytes {0}-{1}/{2}", startPosition, fileLength - 1, fileLength);
}
HttpResponseHeader responseHeader = new HttpResponseHeader();
responseHeader.AcceptRanges = "bytes";
responseHeader.Connection = "Keep-Alive";
responseHeader.ContentDisposition = contentDisposition;
responseHeader.ContentEncoding = Encoding.UTF8;
responseHeader.ContentLength = contentLength;
responseHeader.ContentRange = contentRange;
responseHeader.ContentType = "application/octet-stream";
responseHeader.Etag = eTag;
responseHeader.LastModified = lastUpdateTimeStr;
return responseHeader;
}
/// <summary>
/// Send the download file to the client.
/// </summary>
/// <param name="httpResponse"></param>
/// <param name="responseHeader"></param>
/// <param name="fileStream"></param>
private static void SendDownloadFile(HttpResponse httpResponse, HttpResponseHeader responseHeader, Stream fileStream)
{
if (httpResponse == null || responseHeader == null)
{
return;
}
if (!string.IsNullOrEmpty(responseHeader.ContentRange))
{
httpResponse.StatusCode = 206;
// Set the start position of the reading files.
string[] range = responseHeader.ContentRange.Split(new char[] { ' ','=', '-' });
fileStream.Position = Convert.ToInt64(range[2]);
}
httpResponse.Clear();
httpResponse.Buffer = false;
httpResponse.AppendHeader("Accept-Ranges", responseHeader.AcceptRanges);
httpResponse.AppendHeader("Connection", responseHeader.Connection);
httpResponse.AppendHeader("Content-Disposition", responseHeader.ContentDisposition);
httpResponse.ContentEncoding = responseHeader.ContentEncoding;
httpResponse.AppendHeader("Content-Length", responseHeader.ContentLength);
if (!string.IsNullOrEmpty(responseHeader.ContentRange))
{
httpResponse.AppendHeader("Content-Range", responseHeader.ContentRange);
}
httpResponse.ContentType = responseHeader.ContentType;
httpResponse.AppendHeader("Etag", "\"" + responseHeader.Etag + "\"");
httpResponse.AppendHeader("Last-Modified", responseHeader.LastModified);
Byte[] buffer = new Byte[10240];
long fileLength = Convert.ToInt64(responseHeader.ContentLength);
// Send file to client.
while (fileLength > 0)
{
if (httpResponse.IsClientConnected)
{
int length = fileStream.Read(buffer, 0, 10240);
httpResponse.OutputStream.Write(buffer, 0, length);
httpResponse.Flush();
fileLength = fileLength - length;
}
else
{
fileLength = -1;
}
}
}
}
/// <summary>
/// Respresent the HttpResponse header information.
/// </summary>
class HttpResponseHeader
{
public string AcceptRanges { get; set;}
public string Connection { get; set; }
public string ContentDisposition { get; set; }
public Encoding ContentEncoding { get; set; }
public string ContentLength { get; set; }
public string ContentRange { get; set; }
public string ContentType { get; set; }
public string Etag { get; set; }
public string LastModified { get; set; }
}
}
DownloadHttpHandler.ashx.cs
using System;
using System.Configuration;
using System.Web;
namespace CSASPNETResumeDownload
{
public class DownloadHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string filePath = ConfigurationManager.AppSettings["FilePath"];
Downloader.DownloadFile(context, filePath);
}
public bool IsReusable
{
get { return false; }
}
}
}
If you can consider using ASP.NET Web API, take a look at my post ASP.NET Web API file download service with resume support
It provides a solution using two different approaches: FileStream class and memory mapped files (this may offer some performance benefits).
来源:https://stackoverflow.com/questions/7948316/how-resume-able-file-download-in-asp-net-with-c-sharp-best-way-for-large-fil