zoukankan      html  css  js  c++  java
  • c# 文件的断点续传

    一、开篇描述

    本篇博客所描述的断点续传功能是基于c#语言,服务器端采用.net mvc框架,客户端采用winform框架。

    本篇博客实现断点续传功能的基本思路:1)服务器端是把接收到的文件流,追加到已有的文件;2)客户端是把文件流截段上传;

    其实,任何一种计算机语言基于这个思路(web客户端JavaScript目前例外),都可以实现断点续传的功能。

    二、服务器端

    namespace MvcApplicationUpload.Controllers
    {
        public class HomeController : Controller
        {
            /// <summary>
            /// Index
            /// </summary>
            /// <returns></returns>
            public ActionResult Index()
            {
                //string ip = Request.UserHostAddress;
                //string port = Request.ServerVariables["REMOTE_PORT"].ToString();
                return View();
            }
     
            /// <summary>
            /// Test
            /// </summary>
            /// <returns></returns>
            public ActionResult Test()
            {
                return PartialView();
            }
     
            /// <summary>
            /// 获取续传点。
            /// </summary>
            /// <param name="md5Name"></param>
            /// <returns></returns>
            public string GetFileResumePoint(string md5Name)
            {
                var saveFilePath = Server.MapPath("~/Images/") + md5Name;
                if (System.IO.File.Exists(saveFilePath))
                {
                    var fs = System.IO.File.OpenWrite(saveFilePath);
                    var fsLength = fs.Length.ToString();
                    fs.Close();
                    return fsLength;
                }
                return "0";
            }
     
            /// <summary>
            /// 文件续传。
            /// </summary>
            /// <returns></returns>
            [HttpPost]
            public HttpResponseMessage FileResume()
            {
                var md5Name = Request.QueryString["md5Name"];
                var fileStream = Request.InputStream;
                var contentRange = Request.Headers["Content-Range"];//contentRange样例:bytes 0-1000/5000
                SaveAs(Server.MapPath("~/Images/") + md5Name, fileStream, contentRange);
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
     
            /// <summary>
            /// 给已有文件追加文件流。
            /// </summary>
            /// <param name="saveFilePath"></param>
            /// <param name="stream"></param>
            private void SaveAs(string saveFilePath, System.IO.Stream stream, string contentRange)
            {
                //接收到的碎片字节流信息。
                long startPosition = 0;
                long endPosition = 0;
                if (!string.IsNullOrEmpty(contentRange))
                {
                    contentRange = contentRange.Replace("bytes", "").Trim();
                    contentRange = contentRange.Substring(0, contentRange.IndexOf("/"));
                    string[] ranges = contentRange.Split('-');
                    startPosition = long.Parse(ranges[0]);
                    endPosition = long.Parse(ranges[1]);
                }
                else
                {
                    return;
                }
                //默认写针位置。
                System.IO.FileStream fs;
                long writeStartPosition = 0;
                if (System.IO.File.Exists(saveFilePath))
                {
                    fs = System.IO.File.OpenWrite(saveFilePath);
                    writeStartPosition = fs.Length;
                }
                else
                {
                    fs = new System.IO.FileStream(saveFilePath, System.IO.FileMode.Create);
                }
                //调整写针位置。
                if (writeStartPosition >= endPosition)
                {
                    fs.Close();
                    return;
                }
                else if (writeStartPosition < startPosition)
                {
                    fs.Close();
                    return;
                }
                else if (writeStartPosition > startPosition && writeStartPosition < endPosition)
                {
                    writeStartPosition = startPosition;
                }
                fs.Seek(writeStartPosition, System.IO.SeekOrigin.Current);
                //向文件追加文件流。
                byte[] nbytes = new byte[512];
                int nReadSize = 0;
                while ((nReadSize = stream.Read(nbytes, 0, 512)) > 0)
                {
                    fs.Write(nbytes, 0, nReadSize);
                }
                fs.Close();
            }
     
        }
    }

    三、客户端

    1 界面如下:

    2 代码如下:

    namespace WindowsFormsApplicationUpload
    {
        public partial class Form1 : Form
        {
            /// <summary>
            /// 定义委托。
            /// </summary>
            /// <param name="text"></param>
            delegate void ChangeText(string text);
     
            /// <summary>
            /// 暂停标记。
            /// </summary>
            int flag = 0;
     
            /// <summary>
            /// 上传的文件路径。
            /// </summary>
            string filePath;
     
            /// <summary>
            /// 上传的文件md5值。
            /// </summary>
            string md5Str;
     
            /// <summary>
            /// 上传的文件续传点。
            /// </summary>
            long startPoint;
     
            public Form1()
            {
                InitializeComponent();
            }
     
            /// <summary>
            /// 委托方法。
            /// </summary>
            /// <param name="text"></param>
            public void ChangeLabelText(string text)
            {
                this.label1.Text = text;
            }
     
            /// <summary>
            /// 得到文件的MD5值。
            /// </summary>
            /// <param name="filePath"></param>
            /// <returns></returns>
            public string GetFileMd5(string filePath)
            {
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                Byte[] hashBytes = md5.ComputeHash(fs);
                fs.Close();
                return BitConverter.ToString(hashBytes).Replace("-", "");
            }
     
            /// <summary>
            /// 得到文件的续传点。
            /// </summary>
            /// <param name="md5Str"></param>
            /// <param name="fileExtension"></param>
            /// <returns></returns>
            public long GetFileResumePoint(string md5Str, string fileExtension)
            {
                System.Net.WebClient webClient = new System.Net.WebClient();
                string urlStr = "http://127.0.0.1/Home/GetFileResumePoint?md5Name=" + md5Str + fileExtension;
                byte[] infoBytes = webClient.DownloadData(urlStr);
                string result = System.Text.Encoding.UTF8.GetString(infoBytes);
                webClient.Dispose();
                if (string.IsNullOrEmpty(result))
                {
                    return 0;
                }
                return Convert.ToInt64(result);
            }
     
            public void ResumeFileThread()
            {
                MessageBox.Show(ResumeFile("http://127.0.0.1/Home/FileResume", filePath, startPoint, 1024 * 128, md5Str));
            }
     
            public string ResumeFile(string hostUrl, string filePath, long startPoint, int byteCount, string md5Str)
            {
                string result = "上传成功!";
                if (startPoint < 0)
                {
                    result = "指针有误!";
                    return result;
                }
                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                long fileLength = fs.Length;
                if (startPoint >= fileLength)
                {
                    result = "文件秒传!";
                    return result;
                }
     
                byte[] data;
                System.Net.WebClient webClient = new System.Net.WebClient();
                BinaryReader bReader = new BinaryReader(fs);
                try
                {
                    #region 续传处理
                    if (startPoint >= 1 && startPoint < fileLength)
                    {
                        fs.Seek(startPoint, SeekOrigin.Current);
                    }
                    #endregion
                    #region 分割文件上传
                    int step = byteCount;
                    for (; startPoint < fileLength; startPoint += step)
                    {
                        if (startPoint + byteCount > fileLength)
                        {
                            step = Convert.ToInt32(fileLength - startPoint);
                            data = new byte[step];
                            bReader.Read(data, 0, step);
                        }
                        else
                        {
                            data = new byte[byteCount];
                            bReader.Read(data, 0, byteCount);
                        }
                        webClient.Headers.Set(HttpRequestHeader.ContentRange, "bytes " + startPoint + "-" + (startPoint + step) + "/" + fs.Length);
                        webClient.UploadData(hostUrl + "?md5Name=" + md5Str + Path.GetExtension(filePath), "POST", data);
                        this.BeginInvoke(new ChangeText(ChangeLabelText), (startPoint + step) + "/" + fileLength);
                    pause:
                        if (flag == 1)
                        {
                            Thread.Sleep(1000);
                            goto pause;
                        }
                    }
                    #endregion
                }
                catch (Exception ex)
                {
                    result = ex.Message;
                }
                finally
                {
                    bReader.Close();
                    fs.Close();
                    webClient.Dispose();
                }
                return result;
            }
     
            /// <summary>
            /// 上传按钮点击事件。
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
                OpenFileDialog openFileDialog = new OpenFileDialog();
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    filePath = openFileDialog.FileName;
                    md5Str = GetFileMd5(filePath);
                    startPoint = GetFileResumePoint(md5Str, Path.GetExtension(filePath));
                    ThreadStart ts = new ThreadStart(ResumeFileThread);
                    Thread t = new Thread(ts);
                    t.Start();
                }
            }
     
            /// <summary>
            /// 暂停按钮点击事件。
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button2_Click(object sender, EventArgs e)
            {
                flag = 1;
            }
     
            /// <summary>
            /// 继续按钮点击事件。
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button3_Click(object sender, EventArgs e)
            {
                flag = 0;
            }
     
            /// <summary>
            /// 拖拽上传。
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Form1_Drag(object sender, DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
                    MessageBox.Show("准备上传" + files.Length + "个文件!");
                    foreach (string file in files)
                    {
                        MessageBox.Show("开始上传文件:" + file);
                        filePath = file;
                        md5Str = GetFileMd5(filePath);
                        startPoint = GetFileResumePoint(md5Str, Path.GetExtension(filePath));
                        ThreadStart ts = new ThreadStart(ResumeFileThread);
                        Thread t = new Thread(ts);
                        t.Start();
                    }
                }
            }
     
            private void Form1_DragDrop(object sender, DragEventArgs e)
            {
                //Form1_Drag(sender, e);
            }
     
            private void Form1_DragOver(object sender, DragEventArgs e)
            {
                Form1_Drag(sender, e);
            }
     
        }
    }
  • 相关阅读:
    windows上安装xampp和dvwa
    CentOS 7上安装Vtiger CRM Open Source Edition
    快速建站(lnmp)
    centos7中jdk安装
    centos7中apache安装
    centos7中mysql安装
    再探决策树算法之利用sklearn进行决策树实战
    决策树算法初探
    定制化自己的itchat
    itchat初探
  • 原文地址:https://www.cnblogs.com/siyunianhua/p/15270918.html
Copyright © 2011-2022 走看看