标签:drop mode image format emd pen obj 客户端 split
一、开篇描述
本篇博客所描述的断点续传功能是基于c#语言,服务器端采用.net mvc框架,客户端采用winform框架。
本篇博客实现断点续传功能的基本思路:1)服务器端是把接收到的文件流,追加到已有的文件;2)客户端是把文件流截段上传;
其实,任何一种计算机语言基于这个思路,都可以实现断点续传的功能。
二、服务器端
namespace MvcApp.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { //string ip = Request.UserHostAddress; //string port = Request.ServerVariables["REMOTE_PORT"].ToString(); return View(); } /// <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 fileStream = Request.InputStream; var md5Name = Request.QueryString["md5Name"]; SaveAs(Server.MapPath("~/Images/") + md5Name, fileStream); return new HttpResponseMessage(HttpStatusCode.OK); } /// <summary> /// 给已有文件追加文件流。 /// </summary> /// <param name="saveFilePath"></param> /// <param name="stream"></param> private void SaveAs(string saveFilePath, System.IO.Stream stream) { //接收到的字节信息。 long startPosition = 0; long endPosition = 0; var contentRange = Request.Headers["Content-Range"];//contentRange样例:bytes 10000-20000/59999 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]); } //默认写针位置。 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; nReadSize = stream.Read(nbytes, 0, 512); while (nReadSize > 0) { fs.Write(nbytes, 0, nReadSize); nReadSize = stream.Read(nbytes, 0, 512); } fs.Close(); } } }
三、客户端
1 界面如下:
2 代码如下:
namespace WindowsFormsApplication1 { 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://file.taiji.com/Home/GetFileResumePoint?md5Name=" + md5Str + fileExtension; byte[] infoBytes = webClient.DownloadData(urlStr); string result = System.Text.Encoding.UTF8.GetString(infoBytes); if (string.IsNullOrEmpty(result)) { return 0; } return Convert.ToInt64(result); } public void ResumeFileThread() { MessageBox.Show(ResumeFile("http://file.taiji.com/Home/FileResume", filePath, startPoint, 1024 * 128, md5Str)); } public string ResumeFile(string hostUrl, string filePath, long startPoint, int byteCount, string md5Str) { string result = "上传成功!"; byte[] data; System.Net.WebClient webClient = new System.Net.WebClient(); FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); long fileLength = fs.Length; BinaryReader bReader = new BinaryReader(fs); try { #region 续传处理 if (startPoint == fileLength) { result = "文件秒传!"; } if (startPoint >= 1 && startPoint <= fileLength - 1) { fs.Seek(startPoint, SeekOrigin.Current); } #endregion #region 分割文件上传 for (; startPoint <= fileLength - 1; startPoint = startPoint + byteCount) { int step = 0; if (startPoint + byteCount > fileLength) { data = new byte[Convert.ToInt32(fileLength - startPoint)]; bReader.Read(data, 0, Convert.ToInt32(fileLength - startPoint)); step = Convert.ToInt32(fileLength - startPoint); } else { data = new byte[byteCount]; bReader.Read(data, 0, byteCount); step = byteCount; } webClient.Headers.Remove(HttpRequestHeader.ContentRange); webClient.Headers.Add(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; } bReader.Close(); fs.Close(); 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_Load(object sender, EventArgs e) { this.AllowDrop = true; } /// <summary> /// 拖拽上传。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_DragOver(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(); } } } } }
标签:drop mode image format emd pen obj 客户端 split
原文地址:http://www.cnblogs.com/by-lhc/p/7794350.html