C#集成FastDFS斷點續傳

C#集成FastDFS斷點續傳

參考

.net版本FastDFS客戶端v5.05html

https://github.com/zhouyh362329/fastdfs.client.netgit

FastDFS環境準備github

http://www.cnblogs.com/ddrsql/p/7118695.htmlweb

webuploadersql

http://fex.baidu.com/webuploader/app

普通方式下載

非斷點續傳方式下載。測試

        /// <summary>
        /// 普通下載
        /// </summary>
        public void Download()
        {
            string fileName = "下載測試test.txt";
            string filePath = Server.MapPath("/File/test.txt");

            System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath);

            if (fileInfo.Exists == true)
            {
                const long ChunkSize = 10240;
                byte[] buffer = new byte[ChunkSize];

                Response.Clear();
                System.IO.FileStream iStream = System.IO.File.OpenRead(filePath);
                long dataLengthToRead = iStream.Length;//獲取下載的文件總大小 
                Response.ContentEncoding = Encoding.UTF8;
                Response.ContentType = "application/octet-stream";
                Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
                while (dataLengthToRead > 0 && Response.IsClientConnected)
                {
                    Thread.Sleep(100);
                    int lengthRead = iStream.Read(buffer, 0, Convert.ToInt32(ChunkSize));//讀取的大小 
                    Response.OutputStream.Write(buffer, 0, lengthRead);
                    Response.Flush();
                    dataLengthToRead -= lengthRead;
                }
                Response.Close();
            }
        }

下載完成前客戶端不知道文件大小。this

MVC FastDFS 斷點續傳方式下載

斷點續傳幾個關鍵Header屬性:spa

Request.net

If-Range、Range

Response

StatusCode = 206

Accept-Ranges、ETag、Content-Length、Content-Range

        /// <summary>
        /// FastDFS下載文件,斷點續傳
        /// </summary>
        /// <returns></returns>
        public bool DownloadByFDFS()
        {
            string group_name = "group1";
            string remote_filename = "M00/00/00/CgEG1FlWChOEHXNFAAAAAEFinIM178.txt";
            string fileName = "測試.txt";
            long length = 2878186;

            long speed = 1024 * 100;
            bool ret = true;
            try
            {
                #region--驗證:HttpMethod,請求的文件是否存在
                switch (Request.HttpMethod.ToUpper())
                { //目前只支持GET和HEAD方法
                    case "GET":
                    case "HEAD":
                        break;
                    default:
                        Response.StatusCode = 501;
                        return false;
                }
                #endregion

                #region 定義局部變量
                long startBytes = 0;
                int packSize = 1024 * 10; //分塊讀取,每塊10K bytes
                long fileLength = length;// myFile.Length;

                int sleep = (int)Math.Ceiling(1000.0 * packSize / speed);//毫秒數:讀取下一數據塊的時間間隔
                string lastUpdateTiemStr = "2017-07-18 11:57:54";
                string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + lastUpdateTiemStr;//便於恢復下載時提取請求頭;
                #endregion

                #region--驗證:文件是否太大,是不是續傳,且在上次被請求的日期以後是否被修改過--------------
                //if (myFile.Length > Int32.MaxValue)
                //{//-------文件太大了-------
                //    Response.StatusCode = 413;//請求實體太大
                //    return false;
                //}

                if (Request.Headers["If-Range"] != null)//對應響應頭ETag:文件名+文件最後修改時間
                {
                    //----------上次被請求的日期以後被修改過--------------
                    if (Request.Headers["If-Range"].Replace("\"", "") != eTag)
                    {//文件修改過
                        Response.StatusCode = 412;//預處理失敗
                        return false;
                    }
                }
                #endregion

                try
                {
                    #region -------添加劇要響應頭、解析請求頭、相關驗證-------------------
                    Response.Clear();
                    Response.Buffer = false;
                    //Response.AddHeader("Content-MD5", GetMD5Hash(myFile));//用於驗證文件
                    Response.AddHeader("Accept-Ranges", "bytes");//重要:續傳必須
                    Response.AppendHeader("ETag", "\"" + eTag + "\"");//重要:續傳必須
                    Response.AppendHeader("Last-Modified", lastUpdateTiemStr);//把最後修改日期寫入響應                
                    Response.ContentType = "application/octet-stream";//MIME類型:匹配任意文件類型
                    Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);//s HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", "%20"));

                    Response.AddHeader("Connection", "Keep-Alive");
                    Response.ContentEncoding = Encoding.UTF8;
                    if (Request.Headers["Range"] != null)
                    {//------若是是續傳請求,則獲取續傳的起始位置,即已經下載到客戶端的字節數------
                        Response.StatusCode = 206;//重要:續傳必須,表示局部範圍響應。初始下載時默認爲200
                        string[] range = Request.Headers["Range"].Split(new char[] { '=', '-' });//"bytes=1474560-"
                        startBytes = Convert.ToInt64(range[1]);//已經下載的字節數,即本次下載的開始位置  
                        if (startBytes < 0 || startBytes >= fileLength)
                        {//無效的起始位置
                            return false;
                        }
                    }
                    Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
                    if (startBytes > 0)
                    {//------若是是續傳請求,告訴客戶端本次的開始字節數,總長度,以便客戶端將續傳數據追加到startBytes位置後----------
                        Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
                    }
                    #endregion

                    #region -------向客戶端發送數據塊-------------------
                    //binaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);
                    int maxCount = (int)Math.Ceiling((fileLength - startBytes + 0.0) / packSize);//分塊下載,剩餘部分可分紅的塊數
                    for (int i = 0; i < maxCount && Response.IsClientConnected; i++)
                    {//客戶端中斷鏈接,則暫停
                        if (fileLength - startBytes < packSize)
                            packSize = 0;
                        byte[] fdfs = client.download_file(group_name, remote_filename, startBytes, packSize);
                        Response.BinaryWrite(fdfs);
                        Response.Flush();
                        startBytes = startBytes + packSize;
                        if (sleep > 1) Thread.Sleep(sleep);
                    }
                    #endregion
                }
                catch
                {
                    ret = false;
                }
                finally
                {
                }
            }
            catch
            {
                ret = false;
            }
            return ret;
        }

斷點續傳方式下載文件效果:

MVC FastDFS斷點續傳方式上傳

文件分段上傳至FastDFS首次使用upload_appender_file,以後使用append_file追加。

        public string Upload(HttpPostedFileBase file)
        {
            string group = "";
            string path = "";
            string tempPath = Server.MapPath("~/File/temp.txt");
            byte[] buffer = new byte[file.ContentLength];
            System.IO.Stream fs = (System.IO.Stream)file.InputStream;
            fs.Read(buffer, 0, file.ContentLength);

            NameValuePair[] meta_list = new NameValuePair[4];
            meta_list[0] = new NameValuePair("width", "800");
            meta_list[1] = new NameValuePair("heigth", "600");
            meta_list[2] = new NameValuePair("bgcolor", "#FFFFFF");
            meta_list[3] = new NameValuePair("author", "Mike");
            if (Request.Params["chunk"] == "0" || Request.Params["chunk"] == null)
            {
                string ext = Path.GetExtension(file.FileName).Replace(".", "");
                //fastdfs上傳
                var results = client.upload_appender_file(buffer, ext, meta_list);
                group = results[0];
                path = results[1];
                //臨時存儲group、path
                StreamWriter sw = new StreamWriter(tempPath, false);
                sw.WriteLine(group);
                sw.WriteLine(path);
                sw.Close();

            }
            else
            {
                if (System.IO.File.Exists(tempPath))
                {
                    StreamReader sr = new StreamReader(tempPath);
                    int i = 0;
                    string strReadline = string.Empty;
                    //讀取group、path
                    while ((strReadline = sr.ReadLine()) != null)
                    {
                        if (i == 0)
                            group = strReadline;
                        else if (i == 1)
                            path = strReadline;
                        i++;
                    }
                    sr.Close();
                }
                //文件續傳,fastdfs追加上傳
                var flag = client.append_file(group, path, buffer);
            }

            return "{\"data\":{\"chunked\" : true, \"ext\" : \"exe\"}}";
        }

        public string GetMaxChunk(string md5)
        {
            //根據實際存儲介質返回文件上傳終止的段
            return "{\"data\":0}";
        }

上傳pconline1477535934501.zip文件測試。

 

 

上傳完成後查看/File/temp.txt文件記錄。

到相應的group查看:

 

WEBAPI FastDFS斷點續傳方式下載

WEBAPI中PushStreamContent 推送

        /// <summary>
        /// PushStreamContent 推送
        /// FDFS文件,斷點續傳
        /// </summary>
        /// <returns></returns>
        public HttpResponseMessage GetFileFDFS()
        {
            HttpResponseMessage response = new HttpResponseMessage();
            if (Request.Headers.IfRange != null && Request.Headers.IfRange.EntityTag.ToString().Replace("\"", "") != NowTime)
            {
                response.StatusCode = HttpStatusCode.PreconditionFailed;
                return response;
            }

            string group_name = "group1";
            string remote_filename = "M00/00/00/CgEG1FlWChOEHXNFAAAAAEFinIM178.txt";
            string fileName = "測試.txt";
            long fileLength = 2878186;

            long speed = 1024 * 100;
            long packSize = 1024 * 10;
            int sleep = (int)Math.Ceiling(1000.0 * packSize / speed);//毫秒數:讀取下一數據塊的時間間隔
            ContentInfo contentInfo = GetContentInfoFromRequest(this.Request, fileLength);
            Action<Stream, HttpContent, TransportContext> pushContentAction = (outputStream, content, context) =>
            {
                try
                {
                    int length = Convert.ToInt32((fileLength - 1) - contentInfo.From) + 1;
                    while (length > 0 && packSize > 0)
                    {
                        byte[] fdfs = client.download_file(group_name, remote_filename, contentInfo.From, Math.Min(length, packSize));
                        outputStream.Write(fdfs, 0, fdfs.Length);
                        contentInfo.From = contentInfo.From + fdfs.Length;
                        length -= fdfs.Length;
                        if (sleep > 1) Thread.Sleep(sleep);
                    }
                    //int maxCount = (int)Math.Ceiling((fileLength - contentInfo.From + 0.0) / packSize);//分塊下載,剩餘部分可分紅的塊數
                    //for (int i = 0; i < maxCount && HttpContext.Current.Response.IsClientConnected; i++)
                    //{
                    //    if (fileLength - contentInfo.From < packSize)
                    //        packSize = 0;
                    //    byte[] fdfs = client.download_file(group_name, remote_filename, contentInfo.From, packSize);
                    //    outputStream.Write(fdfs, 0, fdfs.Length);
                    //    contentInfo.From = contentInfo.From + fdfs.Length;
                    //    if (sleep > 1) Thread.Sleep(sleep);
                    //}
                }
                catch (HttpException ex)
                {
                    throw ex;
                }
                finally
                {
                    outputStream.Close();
                }
            };
            response.Content = new PushStreamContent(pushContentAction, new MediaTypeHeaderValue(MimeType));
            //response.Content = new PushStreamContent(pushContentAction);
            SetResponseHeaders(response, contentInfo, fileLength, fileName);
            return response;
        }

demo下載地址:https://pan.baidu.com/s/1i5rDs49

相關文章
相關標籤/搜索