欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-06 19:11:20
前言 上传功能,是大家经常用到了,可能每一个项目都可以会用到。网上到处都有上传功能的代码。比我写的好的有很多。我这里也仅是分享我的代码。 功能实现点 1.单个文件上传; 2...
前言
上传功能,是大家经常用到了,可能每一个项目都可以会用到。网上到处都有上传功能的代码。比我写的好的有很多。我这里也仅是分享我的代码。
功能实现点
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与我取得联系。