.net网站的文件上传读取进度条和断点下载

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.net网站的文件上传读取进度条和断点下载相关的知识,希望对你有一定的参考价值。

文件上传到服务器时的进度读取

 UpfileResult result = new UpfileResult();
 try
 {
     //先把文件预读到内存里,同时计算上传进度

     IServiceProvider provider = (IServiceProvider)HttpContext.Current;
     // 返回 HTTP 请求正文已被读取的部分。    
     HttpWorkerRequest request = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
     // 获取上传大小 
     long length = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
     CheckFileSize(length, info);

     int bytesRead = 0; // 已读数据大小
     int read;          // 当前读取的块的大小 
     int count = 8192;  // 分块大小    
     byte[] buffer;     // 保存所有上传的数据   
     byte[] tempBuff = null;
     if (request != null)
     {
         tempBuff = request.GetPreloadedEntityBody();
     }
     if (tempBuff != null)
     {
         buffer = new byte[length];

         // 分块大小   
         count = tempBuff.Length;

         // 将已上传数据复制过去      
         Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, count);

         // 开始记录已上传大小       
         bytesRead = tempBuff.Length;

         //计算当前上传文件的百分比
         long percent = bytesRead * 100 / length;
         SetPercent(SessionId, percent);

         int ii = 0;
         // 循环分块读取,直到所有数据读取结束         
         while (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded() && bytesRead < length)
         {
             // 如果最后一块大小小于分块大小,则重新分块       
             if (bytesRead + count > length)
             {
                 count = (int)(length - bytesRead);
                 tempBuff = new byte[count];
             }
             // 分块读取      
             read = request.ReadEntityBody(tempBuff, count);
             // 复制已读数据块     
             Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, read);

             // 记录已上传大小   
             bytesRead += read;

             ii++;
             if (ii % 10 == 0)
             {
                 //计算当前上传文件的百分比
                 percent = bytesRead * 100 / length;
                 SetPercent(SessionId, percent);
             }
             if (read == 0)
             {
                 //如果前面读取过文件(Global.asax中的360验证),这里就读不到数据,需避免进入死循环
                 break;
             }
         }
         if (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded())
         {
             // 传入已上传完的数据      //     
             BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
             Type type = request.GetType();
             while ((type != null) && (type.FullName != "System.Web.Hosting.ISAPIWorkerRequest"))
             {
                 type = type.BaseType;
             }
             if (type != null)
             {
                 type.GetField("_contentAvailLength", bindingFlags).SetValue(request, buffer.Length);
                 type.GetField("_contentTotalLength", bindingFlags).SetValue(request, buffer.Length);
                 type.GetField("_preloadedContent", bindingFlags).SetValue(request, buffer);
                 type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
             }
             // 表示上传已结束   
         }
     }

     HttpPostedFile imgFile = _request.Files[0];
     string fileName = imgFile.FileName;
     UpLoadFile(result, imgFile, fileName, info, SessionId);
     SetPercent(SessionId, 100);
     return result;
 }
 catch (Exception ex)
 {
     result.IsOk = false;
     result.ErrMsg = ex.Message;
     return result;
 }

服务器文件的断点下载

/// <summary>
/// 支持断点下载
/// </summary>
/// <param name="Request"></param>
/// <param name="Response"></param>
/// <param name="filePath">文件的物理地址</param>
private void Down(HttpRequest Request, HttpResponse Response, string filePath)
{
    /*断点下载与普通模式不一样的是:
     断点下载的请求头信息里面增加一个属性 RANGE: bytes=100000-
     响应头里 增加一个属性 Content-Range=bytes 100000-19999/20000
     返回状态码为206(Partial Content)
     
    表示头500个字节:Range: bytes=0-499
    表示第二个500字节:Range: bytes=500-999
    表示最后500个字节:Range: bytes=-500
    表示500字节以后的范围:Range: bytes=500-
    第一个和最后一个字节:Range: bytes=0-0,-1
    同时指定几个范围:Range: bytes=500-600,601-999
    */

    // 打开文件
    using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        // 获取文件的大小
        long fileSize = fileStream.Length;
        string range = Request.Headers["Range"];

        Response.Clear();
        Response.AddHeader("Accept-Ranges", "bytes");
        Response.AddHeader("Connection", "Keep-Alive");
        Response.Buffer = false;

        //数据包大小
        int pack = 10240; //10Kb
        int sleep = 0;
        if(this.Speed.HasValue)
        {
            sleep = (int)Math.Floor(1000.0 * 10 / this.Speed.Value);
        }

        long begin = 0;
        long end = fileSize - 1;

        if (!string.IsNullOrEmpty(range))
        {
            //获取请求的范围,如果有多个范围,暂时只处理第一个,Range: bytes=500-600,601-999
            range = range.Replace("bytes=", "");
            range = range.Split(‘,‘)[0];
            string[] region = range.Split(‘-‘);
            string startPoint = region[0].Trim();
            string endPoint = region[1].Trim();
            if (startPoint == "")
            {
                long.TryParse(endPoint, out end);
                begin = fileSize - end;
                end = fileSize - 1;
            }
            else if (endPoint == "")
            {
                long.TryParse(startPoint, out begin);
                end = fileSize - 1;
            }
            else
            {
                long.TryParse(startPoint, out begin);
                long.TryParse(endPoint, out end);
            }

            Response.StatusCode = 206;
            Response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", begin, end, fileSize));
        }
        //以字节流返回数据
        Response.ContentType = "application/octet-stream";
        //Response.ContentEncoding = System.Text.Encoding.UTF8;
        Response.AddHeader("Content-Disposition", "attachment; filename=\"" + HttpUtility.UrlEncode(Request.ContentEncoding.GetBytes(this.FileName)) + "\"");

        long size = end - begin + 1;
        Response.AddHeader("Content-Length", size.ToString());

        // 创建一比特数组
        byte[] buffer = new Byte[pack];
        fileStream.Position = begin;    //设置当前流位置
        // 当文件大小大于0是进入循环
        while (size > 0)
        {
            // 判断客户端是否仍连接在服务器
            if (Response.IsClientConnected)
            {
                // 获取缓冲区中的总字节数.
                int length = fileStream.Read(buffer, 0, pack);

                // 写入数据
                Response.OutputStream.Write(buffer, 0, length);

                // 将缓冲区的输出发送到客户端
                Response.Flush();

                buffer = new Byte[pack];
                size = size - length;

                if (sleep > 0)
                {
                    Thread.Sleep(sleep);
                }
            }
            else
            {
                //当用户断开后退出循环
                size = -1;
            }
        }
    }
}

文件的断点上传,待补充

 

以上是关于.net网站的文件上传读取进度条和断点下载的主要内容,如果未能解决你的问题,请参考以下文章

FTPFTP文件上传下载-支持断点续传

java文件上传下载用哪种技术好?

从进度条和alert的出现顺序来了解浏览器 UI 渲染 & JS进程

怎么用EXTJS写一个进度条和MESSAGE BOX?

大文件上传下载实现思路,分片断点续传代码实现,以及webUpload组件

Python 给下载文件显示进度条和下载时间