标签:
正式开始之前,先写两个常用又容易被我忘掉的文件和流相互转化的方法。
1,文件转流
FileStream fs = new FileStream(filename,FileMode.Open,FileAccess.Read); byte[] infbytes = new byte[(int)fs.Length]; fs.Read(infbytes, 0, infbytes.Length); fs.Close(); return infbytes;
2,流转文件
FileStream fs = new FileStream("D:\inf.dlv",FileMode.Create,FileAccess.Write); fs.Write(infbytes, 0, inf.Length); fs.Close();
目前来说,自己这边网站有两个上传文件(尤其是图片)的方式,一个是通过aspx的文件上传控件直接在pageload里面接受和操作。一个是jquery上传的控件或者用<input type="file">直接上传,我觉得第二中比较具有普遍性,所以最先讨论第二种。
需求:1,接收用户上传的图片。 2,对图片格式和大小有要求。 3,图片需要压缩 。 4,压缩后的图片需要 裁剪,打水印。 5,存到以用户名为名的文件夹下的三个不同的文件夹。 6,以时间戳和随机数命名文件以防止重名。7,接收之后返回新的文件在服务器的相对路径。
第一步:前台页面的代码
有一点需要特别注意,在提交文件的表单中,action="uploadHandler.ashx"这个属性是不能缺少的,是设置表单的MIME编码。默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;只有使用了multipart/form-data,才能完整的传递文件数据,进行接下来的操作。(MIME是一种保证非ASCII码文件在internet上传播的规格)
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <form runat="server" id="form1" method="post" enctype="multipart/form-data" action="uploadHandler.ashx"> <input name="file" type="file" id="upLoad" /> <input name="action" type="hidden" value="uploadImage" /> <input name="s" type="submit" /> </form> </body> </html>
隐藏域是用来设置提交方式的,模拟多种提交,比如文件提交,图片提交,批量提交。
第二部,控制器,这里只写了一种配置,就是上传图片的配置
public void ProcessRequest(HttpContext context) { Handler action = null; switch (context.Request["action"]) { case "uploadimage": action = new UploadHandler(context, new UploadConfig()//从配置文件中读取配置 { AllowExtensions = Config.GetStringList("imageAllowFiles"), PathFormat = Config.GetString("imagePathFormat"), SizeLimit = Config.GetInt("imageMaxSize"), UploadFieldName = Config.GetString("imageFieldName"), }); break; default: break; } action.Process(); }
然后是处理类的基类,是一个抽象类,关于抽象类,虚方法,还有比如base调用父类的构造函数这些都属于C#面向对象多态的内容,这个需要重新写一篇东西来总结。
public abstract class Handler { public Handler(HttpContext context) { this.Request = context.Request; this.Response = context.Response; this.Context = context; this.Server = context.Server; this.Cookies = context.Request.Cookies; } /// <summary> /// 抽象出来的处理程序,必须被子类重写才能使用 /// </summary> public abstract void Process(); /// <summary> /// 给前台返回结果用的方法, /// </summary> /// <param name="response"></param> protected void WriteJson(object response) { string jsonpCallback = Request["callback"], json = JsonConvert.SerializeObject(response); if (String.IsNullOrWhiteSpace(jsonpCallback)) { Response.AddHeader("Content-Type", "text/plain"); Response.Write(json); } else { Response.AddHeader("Content-Type", "application/javascript"); Response.Write(String.Format("{0}({1});", jsonpCallback, json)); } Response.End(); } public HttpRequest Request { get; private set; } public HttpResponse Response { get; private set; } public HttpContext Context { get; private set; } public HttpServerUtility Server { get; private set; } public HttpCookieCollection Cookies { get; set; } }
这个是真正的处理类uploadHandler
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Newtonsoft.Json; using System.IO; namespace imageTest { public class UploadHandler : Handler { //把两个存储类当做本类的属性 public UploadConfig UploadConfig { get; private set; } public UploadResult Result { get; private set; } /// <summary> /// 在派生类中访问基类的构造函数 /// </summary> /// <param name="context"></param> /// <param name="config"></param> public UploadHandler(HttpContext context, UploadConfig config) : base(context) { this.UploadConfig = config; this.Result = new UploadResult() { State = UploadState.Unknown }; } /// <summary> /// 正式的重写这个处理程序 /// </summary> public override void Process() { byte[] uploadFileBytes = null; string uploadFileName = null; HttpPostedFile file = Request.Files[UploadConfig.UploadFieldName]; uploadFileName = file.FileName; if (!CheckFileType(uploadFileName)) { Result.State = UploadState.TypeNotAllow; WriteResult(); return; } if (!CheckFileSize(file.ContentLength)) { Result.State = UploadState.SizeLimitExceed; WriteResult(); return; } //在所有的判断都结束之后,正式的对文件进行处理,这个没写 } private void WriteResult() { this.WriteJson(new { state = GetStateMessage(Result.State), url = Result.Url, title = Result.OriginFileName, original = Result.OriginFileName, error = Result.ErrorMessage }); } private string GetStateMessage(UploadState state) { switch (state) { case UploadState.Success: return "SUCCESS"; case UploadState.FileAccessError: return "文件访问出错,请检查写入权限"; case UploadState.SizeLimitExceed: return "文件大小超出服务器限制"; case UploadState.TypeNotAllow: return "不允许的文件格式"; case UploadState.NetworkError: return "网络错误"; } return "未知错误"; } private bool CheckFileSize(int size) { return size < UploadConfig.SizeLimit; } private bool CheckFileType(string filename) { var fileExtension = Path.GetExtension(filename).ToLower(); return UploadConfig.AllowExtensions.Select(x => x.ToLower()).Contains(fileExtension); } } /// <summary> /// 上传配置对象,主要是用来读取后存放配置数据 /// </summary> public class UploadConfig { /// <summary> /// 文件命名规则 /// </summary> public string PathFormat { get; set; } /// <summary> /// 上传表单域名称 /// </summary> public string UploadFieldName { get; set; } /// <summary> /// 上传大小限制 /// </summary> public int SizeLimit { get; set; } /// <summary> /// 上传允许的文件格式 /// </summary> public string[] AllowExtensions { get; set; } /// <summary> /// 文件是否以 Base64 的形式上传 /// </summary> public bool Base64 { get; set; } /// <summary> /// Base64 字符串所表示的文件名 /// </summary> public string Base64Filename { get; set; } /// <summary> /// 用户的用户名 /// </summary> public string UserName { get; set; } public string WaterUrl { get;set;} public string SmallUrl { get; set; } public string } /// <summary> /// 上传结果对象,主要是用来存储程序的处理结果 /// </summary> public class UploadResult { public UploadState State { get; set; } public string Url { get; set; } public string OriginFileName { get; set; } public string ErrorMessage { get; set; } } /// <summary> /// 枚举类型,程序的处理结果. /// </summary> /// public enum UploadState { Success = 0, SizeLimitExceed = -1, TypeNotAllow = -2, FileAccessError = -3, NetworkError = -4, Unknown = 1, } }
总结一下人家的设计思路,editor最先通过自己的js的配置文件初始化编辑器并且找到路径来访问control.ashx一般处理程序,ashx通过http访问的表单的action来判断是哪种操作,是上传文件还是图片还是读取等等,然后通过这个action,去config.json里面来读取具体的关于文件上传和下载等等配置,把这些配置通过配置对象加上httpcontext上下文一起传到文件上传控制类uploadHandler,uploadHandler继承自handler,所以构造函数可以调用基类的,process方法也是重写基类的抽象方法。
标签:
原文地址:http://www.cnblogs.com/codersun/p/4884571.html