服务器之家

服务器之家 > 正文

asp.net文件上传功能(单文件,多文件,自定义生成缩略图,水印)

时间:2019-09-18 11:10     来源/作者:asp.net空间网

前言 
上传功能,是大家经常用到了,可能每一个项目都可以会用到。网上到处都有上传功能的代码。比我写的好的有很多。我这里也仅是分享我的代码。 
功能实现点 
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\ 或 upload\user\ 等。以\结尾。 
/// 不允许加盘符 
/// </summary> 
public string SaveFolder { get; set; } 
/// <summary> 
/// 自定义生成新的文件夹。 
/// 格式形如: upload\ 或 images\ 或 upload\2011\10\8\ 等。以\结尾。 
/// 最终的文件夹 = 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, 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", requiredFontSize, 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), 0, 0, fromImg.Width, 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, 0, new_width, new_height), new Rectangle(0, 0, 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 += ";\\r\\n"; 

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与我取得联系。 

标签:

相关文章

热门资讯

玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分 2019-06-21
华为nova5pro和p30pro哪个好 华为nova5pro和华为p30pro对比详情
华为nova5pro和p30pro哪个好 华为nova5pro和华为p30pro对比详情 2019-06-22
抖音撒撒累累是什么歌 撒撒累累张艺兴歌曲名字
抖音撒撒累累是什么歌 撒撒累累张艺兴歌曲名字 2019-06-05
男生常说24816是什么意思?女生说13579是什么意思?
男生常说24816是什么意思?女生说13579是什么意思? 2019-09-17
超A是什么意思 你好a表达的是什么
超A是什么意思 你好a表达的是什么 2019-06-06
返回顶部