ResourceMgr是一个可扩展可定制的上传工具类,它提供上传进度和状态指示。配合可视化的组件,有类似于快车或迅雷下载软件的效果。

它的基类的完整实现如下:由于我是在应用程序整体框架中抠出来的代码,所以有些可能是不属于.net自带的类库中的方法。

using System;
using System.IO;
using System.ServiceModel;
using Aosu.Com.Utils;
using Bolan.com.FinancialEditor.Interfaces;
using Bolan.com.FinancialEditor.Utils;
using System.Diagnostics;
using System.Threading;
using System.Configuration;namespace Bolan.com.FinancialEditor.ClassLibs
{/// <summary>/// 资源服务器管理对象,默认实现是WCF, 子类实现是HTTP带进度条/// </summary>public class ResourceMgr{private string _gateway = "";   // 应用程序网关private string _appName = "FinancialEditor";   // 应用程序名,表示资源在资源服务器上被集中管理的根路径。private string _category = "";  // 资源分类标识#region 记录线程状态(wang)/// <summary>/// 计时器,用于监控上传进度/// </summary>protected Stopwatch stopWatch = new Stopwatch();/// <summary>/// 上传线程/// </summary>protected Thread upThread;private string localFilePath;/// <summary>/// 唯一标识,和它对应的文章的OBJECTID保持一致,或者为空/// </summary>public string Id { get; set; }/// <summary>/// 本地文件完全路径名/// </summary>public string LocalFilePath{get { return localFilePath; }set{localFilePath = value;FileInfo fi = new FileInfo(localFilePath);Total = fi.Length;FileName = fi.Name;FileCreateTime = fi.CreationTime;FileEditTime = fi.LastWriteTime;}}/// <summary>/// 不包括文件路径的文件名/// </summary>public string FileName { get; set; }/// <summary>/// 本地文件的创建时间/// </summary>public DateTime FileCreateTime { get; set; }/// <summary>/// 本地文件最后编辑的时间/// </summary>public DateTime FileEditTime { get; set; }/// <summary>/// 上传开始时间/// </summary>public DateTime StartTime { get; set; }/// <summary>/// 上传完成时间/// </summary>public DateTime FinishedTime { get; set; }/// <summary>/// 总字节数/// </summary>public long Total { get; set; }private long finished;/// <summary>/// 已上传完成的字节数/// </summary>public long Finished{get { return finished; }set{if (finished != value){finished = value;if (ProgressChanged != null){ProgressChanged(this);}}}}/// <summary>/// 上传速率,字节/秒/// </summary>public double Speed { get; set; }/// <summary>/// 上传已用去的时间/// </summary>public TimeSpan Elapsed { get; set; }/// <summary>/// 上传剩余时间/// </summary>public TimeSpan Remaining { get; set; }private UploadStatus status;/// <summary>/// 指示处理状态的标志位/// </summary>public UploadStatus Status{get{if ((status < UploadStatus.完成中 && upThread != null && !upThread.IsAlive)){upThread.Abort();status = UploadStatus.等待中;}if ((status == UploadStatus.连接中 && Elapsed.TotalSeconds > 30 && upThread != null)) //长时间连接不上
                {upThread.Abort();status = UploadStatus.等待中;}return status;}set{if (status != value){status = value;if (StatusChanged != null) StatusChanged(this);}}}/// <summary>/// 错误信息/// </summary>public string ErrorMessage { get; set; }public int FinishedPercent{get{return Total == 0 ? 0 : (int)(Finished * 100 / Total);}}public override string ToString(){return String.Format("{0}/{1}KB", Finished / 1024, Total / 1024);}/// <summary>/// 最后上传到的绝对URL地址/// </summary>public string ResultUrl { get; set; }public TransferAction ProgressChanged;public TransferAction StatusChanged;#endregion/// <summary>/// 应用程序网关/// </summary>public string Gateway{get { return _gateway; }set { _gateway = value; }}/// <summary>/// 应用程序名,表示资源在资源服务器上被集中管理的根路径/// </summary>public string AppName{get { return _appName; }set { _appName = value; }}/// <summary>/// 资源分类标识/// </summary>public string Category{get { return _category; }set { _category = value; }}/// <summary>/// 附加信息/// </summary>public object Tag{get;set;}/// <summary>/// 附加属性/// </summary>public string AddinProp { get; set; }protected FileTransferMessage transferMsg;protected FileTransferMessage TransferMsg{get{if (transferMsg == null) CreateUploadMsg();return transferMsg;}}/// <summary>/// 上传文件到资源服务器(同步方式)/// </summary>/// <param name="path">待上传资源的本地路径</param>/// <returns>返回资源的相对路径</returns>public string Upload(string path){stopWatch.Restart();Elapsed = stopWatch.Elapsed;ErrorMessage = "";Status = UploadStatus.连接中;StartTime = DateTime.Now;LocalFilePath = path;CreateUploadMsg();try{DoUpload();Status = UploadStatus.上传完成;FinishedTime = DateTime.Now;Elapsed = stopWatch.Elapsed;Finished = Total;return ResultUrl;}catch (Exception ex){FinishedTime = DateTime.Now;Elapsed = stopWatch.Elapsed;ErrorMessage = ex.Message;Status = UploadStatus.异常;return "";}finally{stopWatch.Stop();}}protected virtual void DoUpload(){ITransfer proxy = SvcChannel.CreateClient<ITransfer>(Gateway, "iUpload");proxy.TransferFile(TransferMsg);// 返回资源的相对路径。
        }public void UploadAsync(){Stop();upThread = new Thread(new ThreadStart(delegate(){Upload(LocalFilePath);}));upThread.Start();}protected static string UploadRootPath = ConfigurationManager.AppSettings["UploadFolder"];protected virtual void CreateUploadMsg(){Id = CommOp.NewId();// 没有指定上传根位置时返回错误if (string.IsNullOrEmpty(_appName)){throw new Exception("未指定上传资源所属的应用名,请与系统管理员联系!");}// 未指定资源的分类if (string.IsNullOrEmpty(_category)){throw new Exception("未指定上传资源所属的分类,请与系统管理员联系!");}// 得到文件信息对象FileInfo fileObject = new FileInfo(LocalFilePath);// 计算资源种子位置string strSeedPath = "";//王家新改,直接new guid避免上传相同文件无效的问题。string strSeedKey = CommOp.NewId();strSeedPath = string.Format("{0}\\{1}\\{2}",_appName,_category,strSeedKey.Substring(0, 2));// 创建文件传输消息对象。transferMsg = new FileTransferMessage();transferMsg.FileName = strSeedKey.Substring(2) + (((".".Equals(fileObject.Extension) || string.IsNullOrEmpty(fileObject.Extension))) ? "" : fileObject.Extension); // 文件名transferMsg.FileData = new FileStream(LocalFilePath, FileMode.Open, FileAccess.Read);    // 文件的数据流transferMsg.UploadFolder = strSeedPath;ResultUrl = new Uri(new Uri(Gateway), "upload\\" + transferMsg.UploadFolder.Replace('\\', '/') + transferMsg.FileName).ToString();}/// <summary>/// 停止上传动作/// </summary>public void Stop(){Status = UploadStatus.等待中;if (upThread != null && upThread.IsAlive){upThread.Abort();}}}public enum UploadStatus{等待中 = 0,连接中,上传中,完成中,上传完成,处理完毕,异常,}/// <summary>/// 资源管理引发的动作/// </summary>/// <param name="mgr"></param>public delegate void TransferAction(ResourceMgr mgr);
}

另外,由于WCF实现的上传没有办法实现进度条,所以我在服务器端提供了常规的asp.net的上传方式:

与此对应的ResourceMgr需要扩展它的实现,因此产生了ResourceMgr2:

    public class ResourceMgr2 : ResourceMgr{// <summary>/// 将本地文件上传到指定的服务器(HttpWebRequest方法)/// </summary>protected override void DoUpload(){string address = String.Format("{0}?app={1}&cat={2}&{3}&{4}", Gateway, AppName, Category, LoginMgr.Instance.VerifyQuery, AddinProp);//时间戳string strBoundary = "----------" + DateTime.Now.Ticks.ToString("x");byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + strBoundary + "\r\n");string strPostHeader = String.Format(@"--{0}
Content-Disposition: form-data; name=""file"" filename=""{1}""
Content-Type:application/octet-stream", strBoundary, new FileInfo(LocalFilePath).Name);byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader);// 根据uri创建HttpWebRequest对象HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(address));httpReq.Method = "POST";//对发送的数据不使用缓存httpReq.AllowWriteStreamBuffering = false;//设置获得响应的超时时间(3600秒)httpReq.Timeout = 3600000;httpReq.ContentType = "multipart/form-data; boundary=" + strBoundary;long fileLength = TransferMsg.FileData.Length;httpReq.ContentLength = TransferMsg.FileData.Length + postHeaderBytes.Length + boundaryBytes.Length; ;//每次上传64kint bufferLength = 65536;byte[] buffer = new byte[bufferLength];//已上传的字节数Finished = 0;Stream postStream = httpReq.GetRequestStream();int size;//发送请求头部消息postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);TransferMsg.FileData.Seek(0, SeekOrigin.Begin);while ((size = TransferMsg.FileData.Read(buffer, 0, bufferLength)) > 0 && Status != UploadStatus.等待中){postStream.Write(buffer, 0, size);Finished += size;Elapsed = stopWatch.Elapsed;Speed = Finished / Elapsed.TotalMilliseconds * 1000; //KBRemaining = new TimeSpan(0, 0, (int)((Total - Finished) / Speed));Speed /= 1024;if (Status == UploadStatus.连接中){Status = UploadStatus.上传中;}}if (Status == UploadStatus.等待中){return;}Status = UploadStatus.完成中;//添加尾部的时间戳postStream.Write(boundaryBytes, 0, boundaryBytes.Length);postStream.Close();//获取服务器端的响应WebResponse webRespon = httpReq.GetResponse();//读取服务器端返回的消息ResultUrl = WebHelper.GetWebResponseText(webRespon);TransferMsg.FileData.Close();}protected override void CreateUploadMsg(){transferMsg = new Interfaces.FileTransferMessage();transferMsg.FileData = new FileStream(LocalFilePath, FileMode.Open, FileAccess.Read);    // 文件的数据流
        }}

对应的服务器端的实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Configuration;
using Bolan.com.FinancialEditor.WebBaseClass;
using Bolan.com.FinancialEditor.Utils;namespace Bolan.com.FinancialEditor
{/// <summary>/// HttpHandler上传文件/// 需要传入的参数: app=应用名&cat=分类名/// 当上传研报时补充:as=是否挂起(0/1)&cid=栏目id & id=文章ID(当文章ID不为空时,处理逻辑有所不同)/// 附加的身份验证信息(uid=用户ID&pwd=加密后的密码&mcode=机器码&sid=会话ID)/// </summary>public class FileUpload : BaseHandler{/// <summary>/// 上传文件保存到服务器的绝对路径/// </summary>public string FilePath;/// <summary>/// 上传文件的客户端文件名/// </summary>public string LocalFileName;/// <summary>/// 服务端返回的文件的完整URL/// </summary>public string RemoteFileUrl;/// <summary>/// 唯一标识,用来在存数据库时决定OBJECTID/// </summary>public string ID;string appName; //应用名string category; //分类名//服务器上传文件的根目录static string UPLOAD_ROOT_FOLDER = ConfigurationManager.AppSettings["UploadFolder"];//服务器上传文件的Web虚拟目录static string VIRTUAL_UPLOAD_ROOT = ConfigurationManager.AppSettings["VirtualUploadRoot"];protected override string GetOutput(){HttpPostedFile hpf = Request.Files[0];appName = Request.QueryString["app"];category = Request.QueryString["cat"];LocalFileName = hpf.FileName;string path = CreatePath();FilePath = Path.Combine(UPLOAD_ROOT_FOLDER, path);string uploadFolder = new FileInfo(FilePath).DirectoryName;// 创建保存文件夹if (!Directory.Exists(uploadFolder)){Directory.CreateDirectory(uploadFolder);}hpf.SaveAs(FilePath);RemoteFileUrl = new Uri(Request.Url, VIRTUAL_UPLOAD_ROOT + '/' + path.Replace('\\', '/')).ToString();if (!String.IsNullOrEmpty(category)){UploadAction.DoAction(category, this);}return RemoteFileUrl;}/// <summary>/// 生成服务端保存文件的路径/// </summary>/// <returns></returns>string CreatePath(){if (string.IsNullOrEmpty(appName)){throw new Exception("未指定上传资源所属的应用名,请与系统管理员联系!");}if (string.IsNullOrEmpty(category)){throw new Exception("未指定上传资源所属的分类,请与系统管理员联系!");}FileInfo fi = new FileInfo(LocalFileName);string rid = CommOp.NewId();//路径分四部分{分类管理路径}/{种子访问效率控制路径}/{资源保存名字部分}{扩展名}string path = string.Format("{0}\\{1}\\{2}\\{3}{4}",appName,category,rid.Substring(0, 2),rid.Substring(2),(((".".Equals(fi.Extension) || string.IsNullOrEmpty(fi.Extension))) ? "" : fi.Extension));return path;}}
}

至于客户端的应用,我给出一个最简单的带进度条的上传对话框:

    public partial class FormUploadProgress : FormGeneral{ResourceMgr resourceMgr;public FormUploadProgress(ResourceMgr mgr){InitializeComponent();resourceMgr = mgr;mgr.ProgressChanged = (mgr1) =>{if (InvokeRequired)Invoke(new MethodInvoker(delegate{progressBarControl1.Position = mgr1.FinishedPercent;}));elseprogressBarControl1.Position = mgr1.FinishedPercent;};mgr.StatusChanged = (mgr1) =>{if (InvokeRequired){Invoke(new MethodInvoker(EndCall));}elseEndCall();};}void EndCall(){if (resourceMgr.Status == UploadStatus.上传完成)DialogResult = DialogResult.OK;else if (resourceMgr.Status == UploadStatus.异常){btnRetry.Enabled = true;lblUploadTips.Text = resourceMgr.ErrorMessage;}}protected override void SetFormAttributes(){LoadAccessOnStart = false;ShowSplashOnStart = false;}protected override void FormInit(){resourceMgr.Status = UploadStatus.等待中;lblUploadTips.Text = "正在上传 " + resourceMgr.LocalFilePath;resourceMgr.UploadAsync();}private void btnCancel_Click(object sender, EventArgs e){resourceMgr.Stop();}private void btnRetry_Click(object sender, EventArgs e){FormInit();}}

运行效果如下:

当然,你可以把若干个ResourceMgr放在一个IList集合里,作为数据源给网络控件,这样就可以显示多个文件同时上传的进度。

另外,它的服务端实现也可扩展,主要扩展点是

服务端的:

if (!String.IsNullOrEmpty(category))
 {
        UploadAction.DoAction(category, this);
 }
这里调用了UploadAction.DoAction()方法,用于执行成功上传完成以后,服务端要完成的善后工作,可能包括留痕、写库或其他业务操作。

UploadAction是一个抽象的基类,它定义如下:

    /// <summary>/// 定义文件上传后需要执行的业务的基类/// </summary>public abstract class UploadAction{/// <summary>/// 执行上传后的行为/// </summary>/// <param name="handler"></param>public abstract void DoAction(FileUpload handler);//生成各上传后业务对象的抽象工厂,为简单,直接写死。今后可以改用配置文件public static UploadActionFactory Factory{get { return new UploadActionFactory(); }}public static void DoAction(string cat, FileUpload handler){var action = Factory.CreateAction(cat);if (action != null) action.DoAction(handler);}}

它的子类可以实现具体的DoAction方法,用于实现具体的业务操作。然后由主调程序通过抽象工厂来瘊定调用哪个UploadAction.

抽象工厂的定义如下:

  /// <summary>/// 工厂类:生成上传后要执行的业务对象/// </summary>public class UploadActionFactory{/// <summary>/// 生成上传操作后要执行的业务/// </summary>/// <param name="act">动作标识符</param>/// <returns>上传后的业务对象</returns>public UploadAction CreateAction(string act){switch (act){case "Files": return new ReportAction();default: return null;}}}

当然,如果只是单纯的上传文件,而没有更多要求,以上的服务端扩展可以无视。

转载于:https://www.cnblogs.com/bwangel/archive/2012/10/26/ResourceMgr.html

在Winform中上传文件的工具类-ResourceMgr相关推荐

  1. SecureCRT从Windows中上传文件lrzsz工具

    系统光盘没有自带的lrzsz包,需从网络下载: yum install -y lrzsz 自动安装即可使用 rz指令为上传 sz指令为下载到PC机上 转载于:https://blog.51cto.co ...

  2. android使用webview上传文件,Android项目中如何在webview页面中上传文件

    Android项目中如何在webview页面中上传文件 发布时间:2020-11-26 15:56:27 来源:亿速云 阅读:68 作者:Leah 本篇文章为大家展示了Android项目中如何在web ...

  3. 随便说说:在ASP.NET应用程序中上传文件

    在Web程序中上传文件是很常见的需求.利用HTTP协议上传文件的方式非常有限,最常见的莫过于使用<input type="file" />元素进行上传.这种上传方式会将 ...

  4. Mac/Linux/Centos终端中上传文件到Linux云服务器

    Mac/Linux/Centos终端中上传文件到Linux云服务器 1.mac上传文件到Linux服务器 scp 文件名 用户名@服务器ip:目标路径如:scp /Users/test/testFil ...

  5. C# winform 上传文件 (多种方案)

    方案一: 注意:要开启虚拟目录的"写入"权限,要不然就报 403 错误 工作中用到winform上传文件(-_-!,很少用winform,搞了半天) 碰到一点问题,解决如下 1.5 ...

  6. C# winform 上传文件 (多种)

    转:http://www.cnblogs.com/7in10/archive/2008/05/20/1203402.html 方案一: 注意:要开启虚拟目录的"写入"权限,要不然就 ...

  7. 日志保存SD卡并上传服务器的工具类

    日志本地写入过于频繁或者积累太多会导致应用卡顿和GC,应当及时或者定期清除文件. package com.bliss.yang.signingapplication.utils;import andr ...

  8. Java代码实现解压文件包和压缩文件的工具类

    最近开发任务比较多,这两天陆陆续续整理了一点资料上传一下,这个是前段时间用到的解压和压缩文件的工具类,网上找了一些,自己补充一下,现在先分享一下,希望对各位同学有所帮助! package com.as ...

  9. 小米开源文件管理器MiCodeFileExplorer-源码研究(8)-文件排序工具类FileSortHelper

    FileSortHelper的核心功能就是,对文件集合FileInfo排序. FileInfo有若干字段,根据字段定义了4种比较器Comparator. 调用示例:Collections.sort(L ...

最新文章

  1. 微服务等于Spring Cloud?了解微服务架构和框架
  2. [渝粤教育] 中国地质大学 金融保险业会计 复习题
  3. git分支合并指定代码_git的几种实用操作(合并代码与暂存复原代码)
  4. 考研英语核心词汇辨析(黑魔方系列2007版之十一)
  5. sublime text3 之 ctags
  6. 嵌入式linux的驱动程序
  7. 续:Fucking 这个网站!
  8. NTFS文件系统详细分析
  9. ArcMap10 批量等距离分割线段
  10. rtx服务器端消息监控插件,RTX2006消息监控插件
  11. 关于城市旅游的HTML网页设计——中国旅游HTML+CSS+JavaScript 出游旅游主题度假酒店 计划出行网站设计
  12. 隐马尔可夫模型拼音汉字输入法
  13. veux--页面刷新更新后数据状态无法保存问题
  14. matlab画微分方程的矢量场图_一维波动方程数值解 Matlab 教程(从入门到出图)——3数值计算的Matlab实现...
  15. 阿里巴巴2016年-校招-实习生岗位-内推
  16. 中国人保为嘉德奥通承保产品责任险,为消费者保驾护航!
  17. 快速增加图片大小KB
  18. 基于ACO蚁群优化的机器人避障算法仿真
  19. JAVA实现在线多人编辑文档,PageOffice---实现多人同时编辑一份文档
  20. 我的web前端工作日志10------疫情过后

热门文章

  1. JNOJ 江南在线评测系统 搭建
  2. CTFshow——命令执行
  3. SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务
  4. 基于MATLAB实现进制数转换
  5. 华为机试 - 最大矩阵和
  6. 组态基于DTU实现机床远程监控系统
  7. DBeaver无法连接SQL Server
  8. uniapp 获取 iphone x 底部黑线高度_你知道 iPhone 可以称重吗?附快捷指令版,更方便...
  9. JPG、GIF、PNG和BMP格式的图片各有什么优点和缺点
  10. 浓情中秋,月满人团圆!联诚发祝您中秋快乐!