| 
                         前言  上传功能,是大家经常用到了,可能每一个项目都可以会用到。网上到处都有上传功能的代码。比我写的好的有很多。我这里也仅是分享我的代码。  功能实现点  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与我取得联系。 
                          (编辑:莱芜站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                     |