asp.net文件上传功能(单文件,多文件,自定义生成缩略图,水印)
发布时间:2020-12-15 20:35:09 所属栏目:asp.Net 来源:网络整理
导读:前言 上传功能,是大家经常用到了,可能每一个项目都可以会用到。网上到处都有上传功能的代码。比我写的好的有很多。我这里也仅是分享我的代码。 功能实现点 1.单个文件上传; 2.多个文件上传; 3.对于图片等类型的图像,可以自定义生成缩略图大小; 4.文件
前言 上传功能,是大家经常用到了,可能每一个项目都可以会用到。网上到处都有上传功能的代码。比我写的好的有很多。我这里也仅是分享我的代码。 功能实现点 1.单个文件上传; 2.多个文件上传; 3.对于图片等类型的图像,可以自定义生成缩略图大小; 4.文件服务器扩展。 模式 主要使用的是“模板方法”的设计模式。 本文章的功能优缺点 1.可以自定义生成缩略图的大小,任意定义。对于像微生活运动户外商城(http://sports.8t8x.com/) 、淘宝网等的网站,他们需要上传大量的商品图片时,非常有用。 2.缺点,我对System.Drawing的命名空间不太熟练,生成图像的方法还是从网上抄的,我觉得我自己得到的这些生成图像的方法,不是非常好。 代码实现 1.接口定义 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace CCNF.Plugin.Upload { /// <summary> /// 上传功能的接口 /// </summary> /// <creator>Marc</creator> public interface IUpload { /// <summary> /// 上传单个文件。 /// </summary> /// <param name="sourcefile"></param> /// <returns></returns> /// <author>Marc</author> int SaveAs(HttpPostedFile sourcefile); } } 2.抽象模板方法类 由于使用代码插入的方式,cnblogs会报错,所以, 我不得不使用原始的copy方式,可能看起来会不太舒服。 复制代码 代码如下: using System; using System.Collections.Generic; using System.Text; using System.Configuration; using System.IO; using System.Net; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D; using System.Web; using System.Collections; namespace CCNF.Plugin.Upload { /// <summary> /// 上传功能。 /// 本类提供上传的一般性方法。 /// </summary> /// <creator>Marc</creator> public abstract class UploadAbstract : IUpload { #region 常量属性 /// <summary> /// 允许上传的文件扩展名。 /// 多个文件扩展名以英文逗号隔开。 /// 默认从Web.config中获取。 /// </summary> private readonly string UPLOADEXTENTION = ConfigurationManager.AppSettings["UploadExtention"]; private string uploadExtention = null; /// <summary> /// 允许上传的文件扩展名。 /// 多个文件扩展名以英文逗号隔开。 /// 默认从Web.config中获取。 /// </summary> public string UploadExtention { get { if (string.IsNullOrEmpty(this.uploadExtention)) { if (string.IsNullOrEmpty(UPLOADEXTENTION)) { throw new Exception("web.config中未配置UploadExtention属性"); } this.uploadExtention = UPLOADEXTENTION; } return this.uploadExtention; } set { this.uploadExtention = value; } } /// <summary> /// 允许上传的单个文件最大大小。 /// 单位为k。 /// 默认从Web.config中获取。 /// </summary> private readonly int UPLOADLENGTH = Convert.ToInt16(ConfigurationManager.AppSettings["UploadLength"]); private int uploadLength = 0; /// <summary> /// 允许上传的单个文件最大大小。 /// 单位为。 /// 默认从Web.config中获取。 /// </summary> public int UploadLength { get { if (this.uploadLength == 0) { this.uploadLength = UPLOADLENGTH; } return this.uploadLength; } set { this.uploadLength = value; } } /// <summary> /// 所上传的文件要保存到哪个物理盘上。 /// 此值为严格的物理文件夹路径。如:E:CCNF /// 注意:必须有盘符。 /// 此属于用于扩展图片服务器数据存储。 /// 默认从Web.config中获取。 /// </summary> private readonly string UPLOADPHYSICALPATH = ConfigurationManager.AppSettings["UploadPhysicalPath"]; private string uploadPhysicalPath = null; /// <summary> /// 所上传的文件要保存到哪个物理盘上。 /// 此值为严格的物理文件夹路径。如:E:CCNF /// 注意:必须有盘符。 /// 此属性用于扩展图片服务器数据存储。 /// 默认从Web.config中获取。 /// </summary> public string UploadPhysicalPath { get { if (string.IsNullOrEmpty(this.uploadPhysicalPath)) { if (string.IsNullOrEmpty(UPLOADPHYSICALPATH)) { throw new Exception("web.config中未配置UploadPhysicalPath属性"); } this.uploadPhysicalPath = UPLOADPHYSICALPATH; } return this.uploadPhysicalPath; } set { this.uploadPhysicalPath = value; } } #endregion #region 枚举 /// <summary> /// 水印类型 /// </summary> public enum WatermarkTypeEnum { /// <summary> /// 文字水印 /// </summary> String = 1, /// <summary> /// 图片水印 /// </summary> Image = 2 } /// <summary> /// 上传结果 /// </summary> protected enum UploadResultEnum { /// <summary> /// 未指定要上传的对象 /// </summary> UploadedObjectIsNull = -9, /// <summary> /// 文件扩展名不允许 /// </summary> ExtentionIsNotAllowed = -2, /// <summary> /// 文件大小不在限定范围内 /// </summary> ContentLengthNotWithinTheScope = -1, /// <summary> /// 未配置或未指定文件的物理保存路径 /// </summary> UploadPhysicalPathNoSpecify = -20, /// <summary> /// 未指定图片水印的相对文件物理路径 /// </summary> ImageWartermarkPathNoSpecify = -30, /// <summary> /// 未指定水印的文字 /// </summary> StringWatermarkNoSpecify = -31, /// <summary> /// 上传原始文件失败 /// </summary> UploadOriginalFileFailure = 0, /// <summary> /// 生成缩略失败 /// </summary> CreateThumbnailImageFailure = -3, /// <summary> /// 未知错误 /// </summary> UnknownError = -4, /// <summary> /// 上传成功 /// </summary> Success = 1 } #endregion #region 上传属性 /// <summary> /// 保存文件夹。 /// 格式形如: upload 或 images 或 uploaduser 等。以结尾。 /// 不允许加盘符 /// </summary> public string SaveFolder { get; set; } /// <summary> /// 自定义生成新的文件夹。 /// 格式形如: upload 或 images 或 upload2011108 等。以结尾。 /// 最终的文件夹 = UploadPhysicalPath + SaveFolder + Folder /// </summary> public string Folder { get; set; } /// <summary> /// 是否生成水印。 /// 默认不启用水印生成。 /// </summary> public bool IsMakeWatermark { get; set; } private int watermarkType = (int)WatermarkTypeEnum.String; /// <summary> /// 生成水印的方式:string从文字生成,image从图片生成。 /// 默认是文字水印 /// </summary> public int WatermarkType { get { return this.watermarkType; } set { this.watermarkType = value; } } /// <summary> /// 水印文字。 /// </summary> public string Watermark { get; set; } /// <summary> /// 水印图片的位置。 /// 提供图片水印的相对位置。 /// 不含盘符。 /// </summary> public string ImageWartermarkPath { get; set; } /// <summary> /// 上传后生成的新文件路径。 /// 此路径为相对物理路径,不含盘符。 /// </summary> public string NewFilePath { get; protected set; } /// <summary> /// 生成缩略图片的长宽, 是一个二维数据。 /// 如:int a[3,2]={{1,2},{5,6},{9,10}}。 /// 如果上传的文件是图片类型,并且希望生成此图片的缩略图,那么请将需要生成的长宽尺寸以数组的方式保存到这里。 /// </summary> public int[,] PicSize { get; set; } /// <summary> /// 生成的图片地址,与二维数组PicSize的长度是对应的。 /// 如果有传入PicSize的数组,那么上传完毕后,系统会返回PicPath数组。 /// 这个数组是它的最终上传路径,以便用户对此值进行数据库操作。 /// 产生的PicPath的索引位置与PicSize是一一对应的。 /// 此属性已声明为只读属性。 /// </summary> public string[] PicPath { get; protected set; } #endregion /// <summary> /// 上传单个文件 /// </summary> /// <param name="sourcefile"></param> /// <param name="upload"></param> /// <returns></returns> /// <author>Marc</author> public virtual int SaveAs(HttpPostedFile sourcefile) { int result = 0; //未知错误 UploadResultEnum uploadResultEnum = UploadResultEnum.UnknownError; if (sourcefile == null) { //未指定要上传的对象 uploadResultEnum = UploadResultEnum.UploadedObjectIsNull; } else { uploadResultEnum = Upload(sourcefile); } result = (int)uploadResultEnum; return result; } /// <summary> /// 上传文件 /// </summary> /// <param name="sourcefile"></param> /// <returns></returns> /// <author>Marc</author> private UploadResultEnum Upload(HttpPostedFile sourcefile) { #region 上传前检测 if (string.IsNullOrEmpty(UploadPhysicalPath)) { //未配置或未指定文件的物理保存路径 return UploadResultEnum.UploadPhysicalPathNoSpecify; } string fileName = sourcefile.FileName; string fileExtention = Path.GetExtension(fileName); if (!CheckExtention(fileExtention)) { //文件扩展名不允许 return UploadResultEnum.ExtentionIsNotAllowed; } int fileLength = sourcefile.ContentLength; if (fileLength <= 0 || fileLength > UploadLength * 1024) { //文件大小不在限定范围内 return UploadResultEnum.ContentLengthNotWithinTheScope; } //创建要保存的文件夹 string physicalPath = UploadPhysicalPath + SaveFolder + Folder; if (!Directory.Exists(physicalPath)) { Directory.CreateDirectory(physicalPath); } #endregion string newFileName = "Ori_" + Guid.NewGuid().ToString() + fileExtention; //新文件相对物理路径 string newFilePath = physicalPath + newFileName; #region 保存原始文件 if (!IsMakeWatermark) //不启用水印时 { //保存文件 sourcefile.SaveAs(newFilePath); } else //要求生成水印 { Image bitmap = new System.Drawing.Bitmap(sourcefile.InputStream); Graphics g = Graphics.FromImage(bitmap); g.InterpolationMode = InterpolationMode.High; g.SmoothingMode = SmoothingMode.AntiAlias; Image fromImg = null; try { //清除整个绘图面并以透明背景色填充 //g.Clear(Color.Transparent); if (WatermarkType == (int)WatermarkTypeEnum.String) //生成文字水印 { if (string.IsNullOrEmpty(Watermark)) { //未指定水印的文字 return UploadResultEnum.StringWatermarkNoSpecify; } Color color = Color.FromArgb(120,255,255); Brush brush = new SolidBrush(color); // 自动根据界面来缩放字体大小 int desiredWidth = (int)(bitmap.Width * .5); Font font = new Font("Arial",16,FontStyle.Regular); SizeF stringSizeF = g.MeasureString(Watermark,font); float Ratio = stringSizeF.Width / font.SizeInPoints; int requiredFontSize = (int)(desiredWidth / Ratio); // 计算图片中点位置 Font requiredFont = new Font("Arial",requiredFontSize,FontStyle.Bold); stringSizeF = g.MeasureString(Watermark,requiredFont); int x = desiredWidth - (int)(stringSizeF.Width / 2); int y = (int)(bitmap.Height * .5) - (int)(stringSizeF.Height / 2); g.DrawString(Watermark,new Font("Verdana",FontStyle.Bold),brush,new Point(x,y)); bitmap.Save(newFilePath,ImageFormat.Jpeg); } else if (WatermarkType == (int)WatermarkTypeEnum.Image) //生成图片水印 { if (string.IsNullOrEmpty(ImageWartermarkPath)) { //未指定图片水印的相对文件物理路径 return UploadResultEnum.ImageWartermarkPathNoSpecify; } fromImg = Image.FromFile(ImageWartermarkPath); g.DrawImage(fromImg,new Rectangle(bitmap.Width - fromImg.Width,bitmap.Height - fromImg.Height,fromImg.Width,fromImg.Height),fromImg.Height,GraphicsUnit.Pixel); bitmap.Save(newFilePath,ImageFormat.Jpeg); } } catch { //上传原始文件失败 return UploadResultEnum.UploadOriginalFileFailure; } finally { if (fromImg != null) { fromImg.Dispose(); } g.Dispose(); bitmap.Dispose(); } } #endregion this.NewFilePath = newFilePath.Replace("","/"); #region 生成各种规格的缩略图 //生成各种规格的缩略图 if (PicSize != null && PicSize.Length > 0) { int width,height; ArrayList picPathArray = new ArrayList(); for (int i = 0; i < PicSize.GetLength(0); i++) { width = PicSize[i,0]; height = PicSize[i,1]; Guid tempGuid = Guid.NewGuid(); //缩略图名称 string thumbnailFileName = physicalPath + tempGuid.ToString() + "_" + width.ToString() + "X" + height.ToString() + fileExtention; if (!SaveThumb(sourcefile,width,height,thumbnailFileName)) { //生成缩略失败 return UploadResultEnum.CreateThumbnailImageFailure; } picPathArray.Add(thumbnailFileName.Replace("","/")); } PicPath = (string[])picPathArray.ToArray(typeof(string)); } #endregion //上传成功 return UploadResultEnum.Success; } /// <summary> /// 生成缩略图 /// </summary> /// <param name="sourcefile"></param> /// <param name="width">生成缩略图的宽度</param> /// <param name="height">生成缩略图的高度</param> /// <param name="thumbnailFileName">缩略图生成路径,含盘符的绝对物理路径。</param> /// <returns></returns> /// <author>Marc</author> private bool SaveThumb(HttpPostedFile sourcefile,int width,int height,string thumbnailFileName) { bool result = false; Image ori_img = Image.FromStream(sourcefile.InputStream); int ori_width = ori_img.Width;//650 int ori_height = ori_img.Height;//950 int new_width = width;//700 int new_height = height;//700 // 在此进行等比例判断,公式如下: if (new_width > ori_width) { new_width = ori_width; } if (new_height > ori_height) { new_height = ori_height; } if ((double)ori_width / (double)ori_height > (double)new_width / (double)new_height) { new_height = ori_height * new_width / ori_width; } else { new_width = ori_width * new_height / ori_height; } Image bitmap = new System.Drawing.Bitmap(new_width,new_height); Graphics g = Graphics.FromImage(bitmap); try { g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.High; g.Clear(System.Drawing.Color.Transparent); g.DrawImage(ori_img,new Rectangle(0,new_width,new_height),ori_width,ori_height),GraphicsUnit.Pixel); bitmap.Save(thumbnailFileName,ImageFormat.Jpeg); result = true; } catch { result = false; } finally { if (ori_img != null) { ori_img.Dispose(); } if (bitmap != null) { bitmap.Dispose(); } g.Dispose(); bitmap.Dispose(); } return result; } /// <summary> /// 检查文件扩展名 /// </summary> /// <param name="extention"></param> /// <returns></returns> protected bool CheckExtention(string extention) { bool b = false; string[] extentions = this.UploadExtention.Split(','); for (int i = 0; i < extentions.Length; i++) { if (extention.ToLower() == extentions[i].ToLower()) { b = true; break; } } return b; } /// <summary> /// 返回上传结果 /// </summary> /// <param name="result">消息集合</param> /// <returns></returns> /// <author>marc</author> public string Error(int[] result) { string s = ""; for (int i = 0; i < result.Length; i++) { s += "第" + (i + 1).ToString() + "张:"; if (result[i] != 1) { switch (result[i]) { case (int)UploadResultEnum.UploadedObjectIsNull: s += "未指定要上传的对象"; break; case (int)UploadResultEnum.ExtentionIsNotAllowed: s += "文件扩展名不允许"; break; case (int)UploadResultEnum.ContentLengthNotWithinTheScope: s += "文件大小不在限定范围内"; break; case (int)UploadResultEnum.UploadPhysicalPathNoSpecify: s += "未配置或未指定文件的物理保存路径"; break; case (int)UploadResultEnum.ImageWartermarkPathNoSpecify: s += "未指定图片水印的相对文件物理路径"; break; case (int)UploadResultEnum.StringWatermarkNoSpecify: s += "未指定水印的文字"; break; case (int)UploadResultEnum.UploadOriginalFileFailure: s += "上传原始文件失败"; break; case (int)UploadResultEnum.CreateThumbnailImageFailure: s += "生成缩略失败"; break; case (int)UploadResultEnum.UnknownError: s += "未知错误"; break; default: break; } } else { s += "上传成功"; } s += ";rn"; } return s; } /// <summary> /// 返回上传结果 /// </summary> /// <param name="result">消息值,int型</param> /// <returns></returns> /// <author>marc</author> public string Error(int result) { string s = null; switch (result) { case (int)UploadResultEnum.UploadedObjectIsNull: s += "未指定要上传的对象"; break; case (int)UploadResultEnum.ExtentionIsNotAllowed: s += "文件扩展名不允许"; break; case (int)UploadResultEnum.ContentLengthNotWithinTheScope: s += "文件大小不在限定范围内"; break; case (int)UploadResultEnum.UploadPhysicalPathNoSpecify: s += "未配置或未指定文件的物理保存路径"; break; case (int)UploadResultEnum.ImageWartermarkPathNoSpecify: s += "未指定图片水印的相对文件物理路径"; break; case (int)UploadResultEnum.StringWatermarkNoSpecify: s += "未指定水印的文字"; break; case (int)UploadResultEnum.UploadOriginalFileFailure: s += "上传原始文件失败"; break; case (int)UploadResultEnum.CreateThumbnailImageFailure: s += "生成缩略失败"; break; case (int)UploadResultEnum.UnknownError: s += "未知错误"; break; case (int)UploadResultEnum.Success: s += "上传成功"; break; default: break; } return s; } } } 所有的实现功能都在这个模板方法中。 主要定义了“常量属性”、“枚举”、“上传属性”, 以及开放方法 SaveAs(HttpPostedFile sourcefile) 和 返回错误消息的方法。 3.具体抽象类的实现,很简单,请看 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace CCNF.Plugin.Upload { /// <summary> /// 上传文件 /// </summary> /// <creator>Marc</creator> public sealed class Upload : UploadAbstract { } } 4.前台处理页面Upload.ashx,注意是处理页面,ashx文件。 复制代码 代码如下: <%@ WebHandler Language="C#" Class="Upload" %> using System; using System.Web; using System.IO; public class Upload : IHttpHandler { public void ProcessRequest(HttpContext context) { HttpResponse response = context.Response; HttpRequest request = context.Request; HttpServerUtility server = context.Server; context.Response.ContentType = "text/plain"; HttpPostedFile httpPostedFile = request.Files["FileData"]; string uploadpath = request["folder"] + "";// server.MapPath(request["folder"] + ""); if (httpPostedFile != null) { CCNF.Plugin.Upload.Upload upload = new CCNF.Plugin.Upload.Upload(); upload.SaveFolder = uploadpath; upload.PicSize = new int[,] { { 200,150 } };//生成缩略图,要生成哪些尺寸规格的缩略图,请自行定义二维数组 int result = upload.SaveAs(httpPostedFile); if (result == 1) { context.Response.Write("1"); } else { throw new Exception(upload.Error(result)); // context.Response.Write("0"); } } } public bool IsReusable { get { return false; } } } 5.前台aspx页面调用ashx页面 这里,我使用了一个第三方控件,因为这不是我本文的重点,所以,只简略说一下这个控件的名字是:jquery.uploadify,各位可以去找一下这个js控件的代码。使用起来很简单的的一个js封装控件。 通过这个js控件,会将页面上传的文件post到ashx处理文件中,ashx会接收数据并开始上传。 后记 一、上传功能遍地都是, 而本文主要的亮点在于自定义生成多个缩略图。这对于像微生活运动户外商城(http://sports.8t8x.com/) 、淘宝网等的网站,非常适用。 二、我再次回顾设计模式,温故而知新,又有新的发现,所以,发此文,聊表慰藉。 关于本文作者 马志远(Marc),1981年,2002年湖北大学肄业,现蜗居广州。2004年学习编程,至今已经有8年的编程经验,长期从事asp.net B/S方面的开发和设计。在项目解决方案上、在项目性能和扩展等上,具有深强的能力。您可以使用mazhiyuan1981@163.com与我取得联系。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- asp.net-mvc – IIS通过http方法重写排除规则
- asp.net-mvc – ASP.NET MVC:使浏览器缓存图像从动作
- asp.net-mvc-3 – ASP.NET性能分析404/500错误
- asp.net – 如何将HTML页面转换为.ASPX页面并向其添加/删除
- asp.net-mvc-2 – 在选择聚合时,如何处理Linq到NHibernate的
- asp.net-mvc – 如何摆脱ASP.NET MVC中的HTML错误报告?
- datetime – 将时间转换为UTC vbScript
- asp.net – 在Inproc模式下与页面只读的会话锁争用
- 如何更改asp.net identity 3(vnext)使用的表名?
- asp.net-mvc – ASP.NET MVC中具有动态数量的texbox的表单
推荐文章
站长推荐
- 从ASP.NET项目中的发布版本中排除页面
- asp.net – 即使在ssl上,在ViewState中存储信用卡
- asp.net – 调整白色图像后获得灰色边框
- asp.net-mvc – Asp.NET MVC 2预览2:Area的aspx
- 在ASP.net Webforms中,如何检测有人按下哪个文本
- asp.net – 是MemoryCache范围会话还是应用程序?
- asp.net – PostBackUrl在Html按钮上不可用
- asp.net – 终止所有会话,然后是应用程序结束事件
- asp.net-mvc – 用于OpenID OAuth简单身份验证的
- asp.net-mvc – web.config中的表单身份验证
热点阅读