如何使用 C# 在 ASP.NET 中恢复文件下载 ->最好的方法(也适用于大文件)

发布于 2024-12-12 22:05:01 字数 3557 浏览 0 评论 0原文

请参阅下面的处理程序:

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;
            }
        }
    }
}  

我使用此处理程序来下载我的文件,而无需直接在浏览器中打开它们 -> (使用查询字符串路径)

如何使我的文件可恢复?

我的互联网下载管理器中没有该选项!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

无边思念无边月 2024-12-19 22:05:02

根据要求,这是答案的“清理”版本:

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;
}

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;
}
相思故 2024-12-19 22:05:02

这就是答案!

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

    }
}

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

    }
}
霊感 2024-12-19 22:05:02

这是 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; }
        }
    }
}

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; }
        }
    }
}
月竹挽风 2024-12-19 22:05:02

现在,使用新版本的 asp.net,您可以使用以下示例代码:

  [HttpGet]
    [Route(nameof(DownloadFileStream))]
    public async Task<FileStreamResult> DownloadFileStream(string pathFile, CancellationToken cancellationToken)
    {
        
        FileStream destination = new FileStream(pathFile,...);
        
        return new FileStreamResult(destination, "application/octet-stream")
        {
            FileDownloadName = "fileName",
            EnableRangeProcessing = true  // this enable the resume abality
        };
    }

Now, with the new version of asp.net you can use this sample code:

  [HttpGet]
    [Route(nameof(DownloadFileStream))]
    public async Task<FileStreamResult> DownloadFileStream(string pathFile, CancellationToken cancellationToken)
    {
        
        FileStream destination = new FileStream(pathFile,...);
        
        return new FileStreamResult(destination, "application/octet-stream")
        {
            FileDownloadName = "fileName",
            EnableRangeProcessing = true  // this enable the resume abality
        };
    }
萌吟 2024-12-19 22:05:02

如果您可以考虑使用 ASP.NET Web API,请查看我的帖子
ASP.NET Web API 文件具有恢复支持的下载服务

它提供了使用两种不同方法的解决方案:FileStream 类和内存映射文件(这可能会带来一些性能优势)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文