关于文件上传..其实要传到服务器很简单就几句代码。不过个人的要求比较多,需要跨域、跨站点、跨目录、记录数据库、生成不同版本缩略图、重复文件不上传、记录Exif信息、记录文件对象关系等。经过了很多次改动了,估计几年前就有一个版本...随着自己的需求不断变更。
首先有一个抽象类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Web.SessionState; using System.IO; using System.Drawing; using System.Collections; using System.Data; using System.Data.Common; using FYJ.Upload.Util; using FYJ.Common; namespace FYJ.Upload.Axd { public abstract class UploadAbstract : IHttpHandler, IRequiresSessionState { // IRequiresSessionState接口 必须写上 否则不能访问Session bool IHttpHandler.IsReusable { get { return false; } } public abstract void ProcessRequest(HttpContext context); #region 属性 /// <summary> /// 单个文件大小限制 0表示不限制 /// </summary> public virtual long MaxSingleLimitSize { get { return 0; } } /// <summary> /// 文件个数限制 0表示不限制 /// </summary> public virtual int MaxCountLimit { get { return 0; } } /// <summary> /// 总文件大小限制 0表示不限制 /// </summary> public virtual long MaxTotalLimitSize { get { return 0; } } /// <summary> /// 允许的图片扩展名 /// </summary> public virtual string ImageExt { get { return "png,jpg,gif,bmp"; } } /// <summary> /// 允许的文件扩展名 null 为不限制 /// </summary> public virtual string FileExt { get { return null; } } /// <summary> /// 扩展名限制 null 为不限制 /// </summary> public virtual Hashtable ExtLimit { get { Hashtable extTable = new Hashtable(); extTable.Add("image", "gif,jpg,jpeg,png,bmp"); extTable.Add("flash", "swf,flv"); extTable.Add("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb"); extTable.Add("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); return ExtLimit; } } /// <summary> /// 除了文件服务器定义的目录外第一个目录名 /// </summary> public virtual string AppName { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["appName"])) { return HttpContext.Current.Request["appName"]; } else { throw new Exception("appName参数不能为空"); } } } public virtual string ThumbMod { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["thumbMod"])) { return HttpContext.Current.Request["thumbMod"]; } else { return "W"; } } } private bool _isLimitImage; /// <summary> /// 获取或设置是否限制只能上传图片 /// </summary> public virtual bool IsLimitImage { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["isLimitImage"])) { if (HttpContext.Current.Request["isLimitImage"] == "1" || HttpContext.Current.Request["isLimitImage"].ToLower() == "true") { return true; } } return _isLimitImage; } set { _isLimitImage = value; } } /// <summary> /// 缩放图片宽 如果thumWidth thumheight 有一个为0 则不缩放 /// </summary> public virtual int ThumWidth { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["thumWidth"])) { return Convert.ToInt32(HttpContext.Current.Request["thumWidth"]); } return 0; } } /// <summary> /// 缩放图片高 如果thumWidth thumheight 有一个为0 则不缩放 /// </summary> public virtual int ThumHeight { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["thumHeight"])) { return Convert.ToInt32(HttpContext.Current.Request["thumHeight"]); } return 0; } } /// <summary> /// 图片大小超过多少KB 则使用缩放 如果为0 则始终缩放 /// </summary> public virtual int ThumPassSizeKB { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["thumPassSizeKB"])) { return Convert.ToInt32(HttpContext.Current.Request["thumPassSizeKB"]); } return 0; } } /// <summary> /// 缩放图片高 如果thumWidth thumheight 有一个为0 则不缩放 /// </summary> public virtual string ObjectID { get { return HttpContext.Current.Request["objectID"]; } } /// <summary> /// 对象类型 /// </summary> public string ObjectType { get { return HttpContext.Current.Request["objectType"]; } } /// <summary> /// 对象标志 /// </summary> public string ObjectTag { get { return HttpContext.Current.Request["objectTag"]; } } private bool isSaveOriginalImage = true; /// <summary> /// 当有缩略图的时候是否保存原图 /// </summary> /// fangyj 2015-5-16 public bool IsSaveOriginalImage { get { if (!String.IsNullOrEmpty(HttpContext.Current.Request["isSaveOriginalImage"])) { if (HttpContext.Current.Request["isSaveOriginalImage"] == "1" || HttpContext.Current.Request["isSaveOriginalImage"].ToLower() == "true") { isSaveOriginalImage = true; } } return isSaveOriginalImage; } set { isSaveOriginalImage = value; } } private string _UploadLocalRootPath; /// <summary> /// 获取或设置保存的本地根目录 /// </summary> public string UploadLocalRootPath { get { if (_UploadLocalRootPath == null) { if (!String.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["uploadLocalRootPath"])) { _UploadLocalRootPath = System.Configuration.ConfigurationManager.AppSettings["uploadLocalRootPath"]; } else { throw new CustomException("Web.config的AppSettings必须配置uploadLocalRootPath"); } } return _UploadLocalRootPath; } set { _UploadLocalRootPath = value; } } private string _UploadResultRootUrl; /// <summary> /// 获取或设置返回结果的根Url路径 /// </summary> public string UploadResultRootUrl { get { if (_UploadResultRootUrl == null) { if (!String.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["uploadResultRootUrl"])) { _UploadResultRootUrl = System.Configuration.ConfigurationManager.AppSettings["uploadResultRootUrl"]; } else { throw new CustomException("Web.config的AppSettings必须配置uploadResultRootUrl"); } } return _UploadResultRootUrl; } set { _UploadResultRootUrl = value; } } /// <summary> /// 获取相对于Bucket+"/"+AppName的下一级目录 /// </summary> public string SubDir { get { return HttpContext.Current.Request["subDir"] == null ? "" : HttpContext.Current.Request["subDir"]; } } /// <summary> /// 获取上传后返回的Url根Url /// </summary> public string UploadLocalUrl { get { return UploadResultRootUrl.TrimEnd('/') + "/upload/" + AppName + (SubDir == "" ? "/" : "/" + SubDir + "/") + DateTime.Now.ToString("yyyy/MM/dd"); } } #endregion #region 限制验证,如果不符合要求则抛出异常 public void ValRequest(HttpContext context) { if (MaxCountLimit > 0 && context.Request.Files.Count > MaxCountLimit) { throw new CustomException(-1, "上传文件个数超出了限制"); } if (MaxTotalLimitSize > 0) { long totalSize = 0; // foreach (HttpPostedFile postedFile in context.Request.Files) 这样貌似不行 for (int i = 0; i < context.Request.Files.Count; i++) { HttpPostedFile postedFile = context.Request.Files[i]; if (postedFile == null || postedFile.ContentLength == 0 || string.IsNullOrEmpty(postedFile.FileName)) { continue; } if (MaxSingleLimitSize > 0 && postedFile.ContentLength > MaxSingleLimitSize) { throw new CustomException(-2, "单个文件大小超出了限制"); } string extension = System.IO.Path.GetExtension(postedFile.FileName).ToLower(); if (IsLimitImage) { if (!FileExt.Contains(extension)) { throw new CustomException(-3, "图片格式不允许"); } } else { if (FileExt != null && (!FileExt.Contains(extension))) { throw new CustomException(-4, "不允许上传的文件后缀"); } } totalSize += postedFile.ContentLength; } if (totalSize > MaxTotalLimitSize) { throw new CustomException(-5, "上传文件总大小超出了限制"); } } } #endregion } }
具体实现类
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; using FYJ.Common; using System.Data; using FYJ.Upload; using FYJ.Upload.Util; using Blogs.Entity; namespace Blogs.UI.Upload { public class FileUploadV2 : FYJ.Upload.Axd.UploadAbstract { public override void ProcessRequest(HttpContext context) { Handler action = null; switch (context.Request["action"]) { case "config": action = new ConfigHandler(context); break; 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; case "uploadscrawl": action = new UploadHandler(context, new UploadConfig() { AllowExtensions = new string[] { ".png" }, PathFormat = Config.GetString("scrawlPathFormat"), SizeLimit = Config.GetInt("scrawlMaxSize"), UploadFieldName = Config.GetString("scrawlFieldName"), Base64 = true, Base64Filename = "scrawl.png" }); break; case "uploadvideo": action = new UploadHandler(context, new UploadConfig() { AllowExtensions = Config.GetStringList("videoAllowFiles"), PathFormat = Config.GetString("videoPathFormat"), SizeLimit = Config.GetInt("videoMaxSize"), UploadFieldName = Config.GetString("videoFieldName") }); break; case "uploadfile": action = new UploadHandler(context, new UploadConfig() { AllowExtensions = Config.GetStringList("fileAllowFiles"), PathFormat = Config.GetString("filePathFormat"), SizeLimit = Config.GetInt("fileMaxSize"), UploadFieldName = Config.GetString("fileFieldName") }); break; case "listimage": action = new ListFileManager(context, Config.GetString("imageManagerListPath"), Config.GetStringList("imageManagerAllowFiles")); break; case "listfile": action = new ListFileManager(context, Config.GetString("fileManagerListPath"), Config.GetStringList("fileManagerAllowFiles")); break; case "catchimage": action = new CrawlerHandler(context); break; default: //action = new NotSupportedHandler(context); break; } if (action != null) { action.Process(); } else { HandleNotUeditorProcessRequest(context); } } #region 处理非Ueditor上传 public void HandleNotUeditorProcessRequest(HttpContext context) { try { //删除文件 if (context.Request["action"] == "DeleteFile") { DeleteFile(context); return; } if (context.Request.Files.Count == 0) { return; } //验证 ValRequest(context); context.Response.ContentType = "text/plain"; context.Response.Charset = "utf-8"; List<UploadResult> resultList = new List<UploadResult>(); for (int i = 0; i < context.Request.Files.Count; i++) { HttpPostedFile postedFile = context.Request.Files[i]; UploadResult result = Save(postedFile.InputStream, postedFile.FileName); resultList.Add(result); } UploadResult lastResult = resultList.Last(); Dictionary<string, object> dic = new Dictionary<string, object>(); dic.Add("error", 0); dic.Add("url", lastResult.Url); dic.Add("fileID", lastResult.ID); dic.Add("relationID", lastResult.RelationID); dic.Add("code", 1); dic.Add("message", "上传成功"); string json = JsonHelper.ToJson(dic); if (HttpContext.Current.Request["mod"] == "kindeditor") { json = "{\"error\":0,\"url\":\"" + lastResult.Url + "\"}"; } context.Response.Write(json); } catch (Exception ex) { Dictionary<string, object> dic = new Dictionary<string, object>(); dic.Add("error", 1); dic.Add("code", -1); dic.Add("message", "上传失败" + ex.Message); string json = JsonHelper.ToJson(dic); context.Response.Write(json); } context.Response.End(); } #endregion private readonly FYJ.Data.IDbHelper db = FYJ.Data.DbFactory.GetIDbHelper("upload"); /// <summary> /// 删除物理文件 /// </summary> /// <param name="fileUrl"></param> /// <param name="fileThumbUrl"></param> private void DeletePhysicsFile(string fileUrl, string fileThumbUrl) { string localPath = ""; if (!String.IsNullOrEmpty(fileUrl) && fileUrl.StartsWith(UploadResultRootUrl)) { localPath = Path.Combine(UploadLocalRootPath, fileUrl.Replace(UploadResultRootUrl, "").TrimStart('/').TrimStart('\\')); //删除大图 if (File.Exists(localPath)) { File.Delete(localPath); } } if (!String.IsNullOrEmpty(fileThumbUrl) && fileThumbUrl.StartsWith(UploadResultRootUrl)) { string thumbPath = Path.Combine(UploadLocalRootPath, fileThumbUrl.Replace(UploadResultRootUrl, "").TrimStart('/').TrimStart('\\')); //删除缩略图 if (thumbPath != localPath) { if (File.Exists(thumbPath)) { File.Delete(thumbPath); } } } } private void DeleteFile(HttpContext context) { string fileUrl = context.Server.UrlDecode(context.Request["fileUrl"]); string objectID = context.Request["objectID"]; string result = DeleteFileByUrl(fileUrl, objectID); if (!String.IsNullOrEmpty(context.Request["callback"])) { context.Response.Write(context.Request["callback"] + "(" + result + ")"); } else { context.Response.Write("{\"code\":1}"); } } public UploadResult Save(Stream input, string fileName, string fromUrl = null) { if (fileName != null) { if (fileName.Equals("Web.config", StringComparison.CurrentCultureIgnoreCase)) { throw new CustomException("不允许上传的文件"); } if (fileName.Equals("crossdomain.xml", StringComparison.CurrentCultureIgnoreCase)) { throw new CustomException("不允许上传的文件"); } if (fileName.Equals("favicon.ico", StringComparison.CurrentCultureIgnoreCase)) { throw new CustomException("不允许上传的文件"); } } List<byte> data = new List<byte>(); byte[] buffer = new byte[4096]; int read = input.Read(buffer, 0, buffer.Length); while (read > 0) { for (int i = 0; i < read; i++) { data.Add(buffer[i]); } read = input.Read(buffer, 0, buffer.Length); } input.Close(); var arr = data.ToArray(); UploadResult result = new UploadResult(); result.ID = Guid.NewGuid().ToString("N"); //获取sha1 System.Security.Cryptography.HashAlgorithm algorithm = System.Security.Cryptography.SHA1.Create(); String sha1 = BitConverter.ToString(algorithm.ComputeHash(arr)).Replace("-", ""); blog_tb_file fileEntity = FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFile>.Instance.GetEntity(sha1, AppName); string extension = System.IO.Path.GetExtension(fileName).ToLower(); bool isImage = (extension == ".jpg" || extension == ".png" || extension == ".bmp" || extension == ".gif"); //如果文件不存在 if (fileEntity == null) { fileEntity = new blog_tb_file(); fileEntity.fileID = Guid.NewGuid().ToString("N"); fileEntity.fileName = fileName; string uploadLocalPath = Path.Combine(UploadLocalRootPath, "upload", AppName, SubDir, DateTime.Now.ToString("yyyy/MM/dd")); string testname = HttpUtility.UrlDecode(fileName); int ai = 1; while (File.Exists(Path.Combine(uploadLocalPath, testname))) { testname = Path.GetFileNameWithoutExtension(fileName) + "_" + ai++ + Path.GetExtension(fileName); } result.FileName = testname; //如果是图片 if (isImage) { fileEntity.fileIsImage = true; //如果要上传原图 if (IsSaveOriginalImage) { string localPath = uploadLocalPath.TrimEnd('/') + "/" + testname; fileEntity.fileSha1 = sha1; fileEntity.fileSize = arr.Length; //获取MD5 algorithm = System.Security.Cryptography.MD5.Create(); String md5 = BitConverter.ToString(algorithm.ComputeHash(arr)).Replace("-", ""); fileEntity.fileMd5 = md5; //获取宽高 MemoryStream ms = new MemoryStream(arr); ms.Write(arr, 0, arr.Length); System.Drawing.Bitmap map = new System.Drawing.Bitmap(ms); fileEntity.Width = map.Width; fileEntity.Height = map.Height; ms.Close(); map.Dispose(); //文件夹路径 string uploadFolder = Path.GetDirectoryName(localPath); if (!Directory.Exists(uploadFolder)) { Directory.CreateDirectory(uploadFolder); } //上传文件 --原图 File.WriteAllBytes(localPath, arr); fileEntity.fileUrl = UploadLocalUrl.TrimEnd('/') + "/" + testname; } //缩放图片 if (ThumHeight != 0 && ThumWidth != 0 && (ThumPassSizeKB == 0 || arr.Length > ThumPassSizeKB * 1024) && ThumbMod.ToLower() != "none") { string localThumbPath = uploadLocalPath.TrimEnd('/') + "/thumb" + ThumWidth + "x" + ThumHeight + "/" + testname; //处理缩略图 blog_tb_fileThumb thumbEntity = CreateThumb(localThumbPath, testname, arr); thumbEntity.FileID = fileEntity.fileID; thumbEntity.ADD_DATE = DateTime.Now; thumbEntity.UPDATE_DATE = DateTime.Now; //保存缩略图数据到数据库 FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFile>.Instance.SaveThumb(thumbEntity); //如果原图地址不存在 则赋值为缩略图 if (fileEntity.fileUrl == null) { fileEntity.fileUrl = thumbEntity.ThumbUrl; } fileEntity.fileThumbUrl = thumbEntity.ThumbUrl; fileEntity.ThumbSize = (int)thumbEntity.Size; fileEntity.ThumbWidth = ThumWidth; fileEntity.ThumbHeight = ThumHeight; } //处理exif System.IO.MemoryStream m = new MemoryStream(arr); try { System.Drawing.Bitmap map = new System.Drawing.Bitmap(m); ExifHelper helper = new ExifHelper(map); if (helper.HasExif) { string exifString = helper.ToString(); fileEntity.Exif = exifString; map.Dispose(); //插入exif信息 blog_tb_Exif exifEntity = new blog_tb_Exif(); exifEntity.FileID = result.ID; exifEntity.Aperture = helper.Aperture; exifEntity.Balance = helper.Balance; exifEntity.Camera = helper.Camera; exifEntity.Exposure = helper.Exposure; exifEntity.Flashlight = helper.Flashlight; exifEntity.Focus = helper.Focus; exifEntity.ISO = helper.ISO; exifEntity.Lens = helper.Lens; exifEntity.Mode = helper.Mode; exifEntity.Metering = helper.Metering; exifEntity.ShotDate = helper.ShotDate; exifEntity.Shutter = helper.Shutter; FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFile>.Instance.AddExif(exifEntity); } } catch { } finally { m.Close(); m.Dispose(); } } else //非图片文件上传原文件 { string localPath = uploadLocalPath.TrimEnd('/') + "/" + testname; //文件夹路径 string uploadFolder = Path.GetDirectoryName(localPath); if (!Directory.Exists(uploadFolder)) { Directory.CreateDirectory(uploadFolder); } //上传文件 File.WriteAllBytes(localPath, arr); } fileEntity.fileKey = Guid.NewGuid().ToString("N"); fileEntity.fileFromUrl = fromUrl; fileEntity.appName = AppName; fileEntity.ADD_DATE = DateTime.Now; fileEntity.UPDATE_DATE = DateTime.Now; //写数据库 FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFile>.Instance.Insert(fileEntity); result.Url = fileEntity.fileUrl; result.ThumbUrl = fileEntity.fileThumbUrl; } else //源文件存在 { result.FileName = fileEntity.fileName; ; if (isImage) { List<blog_tb_fileThumb> thumbs = FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFile>.Instance.GetThumbs(fileEntity.fileID); blog_tb_fileThumb thumbEntity = thumbs.Where(x => x.FileID == fileEntity.fileID && x.Width == ThumWidth && x.Height == ThumHeight).FirstOrDefault(); //如果此规格的缩略图不存在 if (thumbEntity == null || thumbEntity.ID == null) { string uploadLocalPath = Path.Combine(UploadLocalRootPath, "upload", AppName, SubDir, DateTime.Now.ToString("yyyy/MM/dd")); string testname = HttpUtility.UrlDecode(fileName); int ai = 1; while (File.Exists(Path.Combine(uploadLocalPath, testname))) { testname = Path.GetFileNameWithoutExtension(fileName) + "_" + ai++ + Path.GetExtension(fileName); } string localThumbPath = uploadLocalPath.TrimEnd('/') + "/thumb" + ThumWidth + "x" + ThumHeight + "/" + testname; //处理缩略图 thumbEntity = CreateThumb(localThumbPath, testname, arr); thumbEntity.FileID = fileEntity.fileID; thumbEntity.ADD_DATE = DateTime.Now; thumbEntity.UPDATE_DATE = DateTime.Now; //保存缩略图数据到数据库 FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFile>.Instance.SaveThumb(thumbEntity); result.ThumbUrl = thumbEntity.ThumbUrl; } else { result.ThumbUrl = fileEntity.fileThumbUrl; } } result.Url = fileEntity.fileUrl; } if (!String.IsNullOrEmpty(ObjectID)) { //保存数据库文件关系 result.RelationID = FYJ.Framework.Core.IocHelper<Blogs.IBLL.IBLLFileRelation>.Instance.SaveFileRelation(result.ID, ObjectID, ObjectType, ObjectTag); } //如果有缩略图地址 则只返回缩略图 fangyj 2015-5-16 if (!String.IsNullOrEmpty(result.ThumbUrl)) { result.Url = result.ThumbUrl; } return result; } private blog_tb_fileThumb CreateThumb(string localThumbPath, string testname, byte[] arr) { blog_tb_fileThumb thumbEntity = new blog_tb_fileThumb(); //缩略图需要缩放宽高 可能不是实际宽高 thumbEntity.Width = ThumWidth; thumbEntity.Height = ThumHeight; //生成缩略图 if (!Directory.Exists(Path.GetDirectoryName(localThumbPath))) { Directory.CreateDirectory(Path.GetDirectoryName(localThumbPath)); } MemoryStream ms = new MemoryStream(arr); ms.Write(arr, 0, arr.Length); ImageHelper.MakeThumbnail(ms, localThumbPath, ThumWidth, ThumHeight, ThumbMod); ms.Close(); thumbEntity.ThumbUrl = UploadLocalUrl.TrimEnd('/') + "/thumb" + ThumWidth + "x" + ThumHeight + "/" + testname; byte[] thumbArr = System.IO.File.ReadAllBytes(localThumbPath); thumbEntity.Size = thumbArr.Length; //获取缩略图sha1 System.Security.Cryptography.HashAlgorithm algorithm = System.Security.Cryptography.SHA1.Create(); thumbEntity.SHA1 = BitConverter.ToString(algorithm.ComputeHash(thumbArr)).Replace("-", ""); //获取缩略图MD5 algorithm = System.Security.Cryptography.MD5.Create(); thumbEntity.MD5 = BitConverter.ToString(algorithm.ComputeHash(thumbArr)).Replace("-", ""); //获取缩略图真实宽高 ms = new MemoryStream(thumbArr); ms.Write(thumbArr, 0, thumbArr.Length); System.Drawing.Bitmap map = new System.Drawing.Bitmap(ms); //真实宽高 thumbEntity.RealWidth = map.Width; thumbEntity.RealHeight = map.Height; ms.Close(); map.Dispose(); return thumbEntity; } } }
[1楼] 8/9/2015 3:49:19 PM 202.99.196....
ddddddddddd