• 基于HTTP的断点传输


    最近项目需要做一个类似于迅雷的文件下载功能,这类需求可能比较常见,希望可以帮助到有需要的同学

    要求:

    1.支持断点传输

    2. 多文件同时下载

    3. 由于是客户内部试用,服务器只支持HTTP文件下载不支持FTP文件(并没有用户权限的要求)

    由于根据服务器传来的Json字符串解析后进行下载,首先构建Json对象,推荐一个库Newtonsoft.Json

     public class DownloadFile
        {
            [JsonProperty("police_num")]
            public string PoliceNumber { get; set; }
    
            [JsonProperty("equipment_num")]
            public string EquipmentNumber { get; set; }
    
            [JsonProperty("upload_date")]
            public DateTime UploadDateTime { get; set; }
    
            [JsonProperty("type")]
            public string FileType { get; set; }
    
            [JsonProperty("file_name")]
            public string FileName { get; set; }
    
            [JsonProperty("file_path")]
            public string FilePath { get; set; }
        }
    JsonProperty不区分大小写

    public class DownloadTask : ObservableObject
        {
            /// <summary>
            /// </summary>
            public static readonly int BufferSize = 1024;
    
            /// <summary>
            ///     一次请求大小,每次请求100kb
            /// </summary>
            public static long Step = 1024*100;
    
            private int _process;
    
            /// <summary>
            ///     下载文件参数
            /// </summary>
            public DownloadFile DownloadFile { get; set; }
    
            /// <summary>
            ///     下载文件状态
            /// </summary>
            public SegmentState SegmentState { get; set; }
    
            /// <summary>
            ///     默认存储路径
            /// </summary>
            public string DefaultDirectory { get; set; }
    
            /// <summary>
            ///     当前进度
            /// </summary>
            public long CurrentSize { get; set; }
    
            /// <summary>
            ///     文件流对象,用于生成文件
            /// </summary>
            public FileStream FileStream { get; set; }
    
            /// <summary>
            ///     下载起始位置
            /// </summary>
            public long RangeFrom { get; set; }
    
            /// <summary>
            ///     总大小
            /// </summary>
            public long TotalSize { get; set; }
    
            /// <summary>
            ///     链接地址
            /// </summary>
            public string Url { get; set; }
    
            /// <summary>
            ///     界面显示进度
            /// </summary>
            public int Process
            {
                get { return _process; }
                set
                {
                    _process = value;
                    RaisePropertyChanged("Process");
                }
            }
        }

    下载服务类,DownloaderService.cs,功能包括启动下载,暂停,针对文件是否存在进行初始化,获取文件大小方便界面显示
     public class DownloaderService
        {
    
            public void OnStart(DownloadTask downloadTask)
            {
                if (!InitService(downloadTask)) return;
                var downloadThread = new Thread(BeginDownloadFile) { IsBackground = true };
                downloadThread.Start(downloadTask);
            }
    
            public void OnStop(DownloadTask downloadTask)
            {
                downloadTask.SegmentState = SegmentState.Paused;
            }
    
            private bool InitService(DownloadTask downloadTask)
            {
                try
                {
                    if (string.IsNullOrEmpty(downloadTask.Url))
                    {
                        return false;
                    }
    
                    downloadTask.DownloadFile.FileName = downloadTask.Url.Substring(downloadTask.Url.LastIndexOf('/') + 1);
    
                    var fullName = Path.Combine(downloadTask.DefaultDirectory, downloadTask.DownloadFile.FileName);
    
                    if (File.Exists(fullName))
                    {
                        if (downloadTask.TotalSize == 0)
                        {
                            GetTotalSize(downloadTask);
                        }
                        if (downloadTask.CurrentSize == downloadTask.TotalSize)
                        {
                            if (MessageBox.Show("文件已经存在是否覆盖此文件", "TCL", MessageBoxButton.YesNo, MessageBoxImage.Information) !=
                            MessageBoxResult.Yes)
                                return false;
                            File.Delete(fullName);
                            downloadTask.CurrentSize = 0;
                        }
                        downloadTask.FileStream = new FileStream(fullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                        downloadTask.SegmentState = SegmentState.Downloading;
                        return true;
                    }
                    downloadTask.SegmentState = SegmentState.Downloading;
                    downloadTask.FileStream = new FileStream(fullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                    return true;
                }
                catch (Exception ex)
                {
                    LogLightConsole.WriteLog(ex.ToString(), EunmMsgType.Error);
                    return false;
                }
            }
    
            private void BeginDownloadFile(object obj)
            {
                try
                {
                    var downloadTask = (DownloadTask)obj;
                    while (true)
                    {
                        if (downloadTask.SegmentState == SegmentState.Paused)
                        {
                            downloadTask.FileStream.Close();
                            break;
                        }
                        //从0计数,需要减一
                        var from = downloadTask.CurrentSize;
                        if (from < 0)
                        {
                            from = 0;
                        }
    
                        var to = downloadTask.CurrentSize + DownloadTask.Step - 1;
                        if (to >= downloadTask.TotalSize && downloadTask.TotalSize > 0)
                        {
                            to = downloadTask.TotalSize - 1;
                        }
                        if (downloadTask.TotalSize == 0)
                        {
                            GetTotalSize(downloadTask);
                        }
                        if (from >= downloadTask.TotalSize || downloadTask.CurrentSize >= downloadTask.TotalSize)
                        {
                            downloadTask.SegmentState = SegmentState.Finished;
                            downloadTask.FileStream.Close();
                            downloadTask.Process = 100;
                            return;
                        }
    
                        var request = (HttpWebRequest)WebRequest.Create(downloadTask.Url);
                        //request.Method = "GET";            
                        request.AddRange("bytes", from, to);
                        request.Timeout = 1000 * 20;
                        var response = (HttpWebResponse)request.GetResponse();
                        var buffer = new byte[1024];
                        using (var stream = response.GetResponseStream())
                        {
                            if (stream != null)
                            {
                                var size = stream.Read(buffer, 0, buffer.Length);
                                while (size > 0)
                                {
                                    //只将读出的字节写入文件
                                    downloadTask.FileStream.Write(buffer, 0, size);
                                    downloadTask.CurrentSize += size;
                                    size = stream.Read(buffer, 0, buffer.Length);
                                    downloadTask.Process = (int)(downloadTask.CurrentSize * 100 / downloadTask.TotalSize);
                                    downloadTask.FileStream.Flush();
                                }
                            }
                            //如果返回的response头中Content-Range值为空,说明服务器不支持Range属性,不支持断点续传,返回的是所有数据
                            if (response.Headers["Content-Range"] == null)
                            {
                                downloadTask.SegmentState = SegmentState.Finished;
                            }
                        }
                    }
    
                }
                catch (Exception ex)
                {
                    LogLightConsole.WriteLog("BeginDownloadFile" + ex, EunmMsgType.Error);
                }
            }
    
            /// <summary>
            ///     获取文件总大小
            /// </summary>
            public void GetTotalSize(DownloadTask downloadTask)
            {
                var request = (HttpWebRequest)WebRequest.Create(downloadTask.Url);
                //request.Method = "POST";
                //request.Headers.Add("charset:" + "utf-8");
                request.Timeout = 1000 * 20;
                var response = (HttpWebResponse)request.GetResponse();
                downloadTask.TotalSize = response.ContentLength;
            }
        }

    HTTP 1.1版本本身已经扩展了断点传输功能,但是这需要服务器同时也支持,这只是提供了一个简单的例子,具体的针对数据上下文以及成功失败的callback函数,就是做一下委托封装用就好,如果具体使用有什么问题可以私信我,谢谢大家支持!

    response.Headers["Content-Range"] == null 说明服务器不支持断点传输


     
  • 相关阅读:
    【bzoj1010-toy】斜率优化入门模板
    【bzoj1096-仓库建设】斜率优化
    【bzoj1911-[Apio2010]特别行动队】斜率优化
    【bzoj1597- [Usaco2008 Mar]土地购买】斜率优化
    【bzoj4310/hdu5030-跳蚤】后缀数组
    【bzoj2219-数论之神】求解x^a==b(%n)-crt推论-原根-指标-BSGS
    HDU6301 Distinct Values (多校第一场1004) (贪心)
    HDU6299 Balanced Sequence (多校第一场1002) (贪心)
    HDU6298 Maximum Multiple (多校第一场1001)
    NYOJ1238 最小换乘 (dijkstra)
  • 原文地址:https://www.cnblogs.com/dongqinnanren/p/6039438.html
Copyright © 2020-2023  润新知