代码改变世界

ASP.NET 中如何通过编码的方式限制文件的下载速度

2012-07-28 00:01  音乐让我说  阅读(473)  评论(0编辑  收藏  举报

有时候,在处理客户端请求下载文件时,为了避免服务器一次缓冲一个大文件到内存,然后发给客户端来下载,常常需要禁用服务器端的缓冲,一点一点地发送给客户端,这样的好处是不用占用大多的服务器内存,万一客户端终止下载,也可以随时停止响应。

废话不多说,直接贴代码了:

前台代码:

<form id="form1" runat="server">
<div>
    请选择下载速度:
    <asp:DropDownList ID="ddlDonwloadSpeed" runat="server">
        <asp:ListItem Value="20">20 Kb/s</asp:ListItem>
        <asp:ListItem Value="50">50 Kb/s</asp:ListItem>
        <asp:ListItem Value="80">80 Kb/s</asp:ListItem>
    </asp:DropDownList>
    <asp:Button ID="btnDownload" runat="server" Text="开始下载" OnClick="btnDownload_Click" />
</div>
</form>

 

后台代码:

public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if(!IsPostBack)
        {
            GenerateFile();
        }
    }

    /// <summary>
    /// 在服务器上生成一个 dat 文件
    /// </summary>
    protected void GenerateFile()
    {
        int length = 1024 * 1024 * 1;   // 1024 * 1024 * 1 = 1 Mb
        byte[] buffer = new byte[length];

        string filepath = Server.MapPath("~/bigFileSample.dat");
        using (FileStream fs = new FileStream(filepath, FileMode.Create, FileAccess.Write))
        {
            fs.Write(buffer, 0, length);
        }
    }

    /// <summary>
    /// 下载事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnDownload_Click(object sender, EventArgs e)
    {
        string outputFileName = "bigFileSample.dat";
        string filePath = Server.MapPath("~/bigFileSample.dat");

        string value = ddlDonwloadSpeed.SelectedValue;

        // 1024 * 20 = 20 Kb/s.
        int downloadSpeed = 1024 * int.Parse(value);

        Response.Clear();

        try
        {
            DownloadFileWithLimitedSpeed(outputFileName, filePath, downloadSpeed);
        }
        catch (Exception ex)
        {
            Response.Write(@"<p><font color=""red"">");
            Response.Write(ex.Message);
            Response.Write(@"</font></p>");
        }
        Response.End();
    }

    /// <summary>
    /// 处理下载业务
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="filePath">文件的路径</param>
    /// <param name="downloadSpeed">下载速度</param>
    public void DownloadFileWithLimitedSpeed(string fileName, string filePath, long downloadSpeed)
    {
        if (!File.Exists(filePath))
        {
            throw new Exception("错误,这里没有文件供下载!");
        }

        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            using (BinaryReader br = new BinaryReader(fs))
            {
                //获取或设置一个值,该值指示是否缓冲输出并在处理完整个响应之后发送它
                //我们不使用缓冲
                Response.Buffer = false;

                long fileLength = fs.Length;

                // 包的最小大小为 1024 = 1 Kb.
                int pack = 1024;

                // 最初的公式: sleep = 1000 / (downloadspeed / pack)
                // 等同于: 1000.0 * pack / downloadSpeed.
                // 这里还有 1000 毫秒的停顿: 1000 millisecond = 1 second
                int sleep = (int)Math.Ceiling(1000.0 * pack / downloadSpeed);

                Response.AddHeader("Content-Length", fileLength.ToString());
                Response.ContentType = "application/octet-stream";

                string utf8EncodingFileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);
                Response.AddHeader("Content-Disposition", "attachment;filename=" + utf8EncodingFileName);

                int maxCount = (int)Math.Ceiling(Convert.ToDouble(fileLength) / pack);

                for (int i = 0; i < maxCount; i++)
                {
                    if (Response.IsClientConnected)
                    {
                        Response.BinaryWrite(br.ReadBytes(pack));

                        // 这里如果不停顿,则下载会以最大的速度下载。
                        Thread.Sleep(sleep);
                    }
                    else
                    {
                        break;
                    }
                }

            }
        }
    }
}

 

谢谢浏览!