标签: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