文件上传~Uploadify上传控件

时间:2023-03-08 18:28:10

对于文件上传来说,有很多种实现方式,如传统的表单方式,现在流行的flash方式,甚至还有纯JS方式,之所以有这些方式来实现文件上传,我想主要原因是因为,传统的上传对于大文件支持不够,因为它是单线程同步机制,当大文件通过HTTP方式发送到服务端时,对于服务端站点的主线程影响比较大,会产生阻塞,所以,现在很多上传控制都是异步,多线程的方式去实现的.

今天来介绍一个文件上传控制,它就是Uploadify,它应该是flash的异步上传工具,对于大文件支持还不错,所以,我选择了它.

相关API介绍

uploader : uploadify.swf 文件的相对路径,该swf文件是一个带有文字BROWSE的按钮,点击后淡出打开文件对话框,默认值:uploadify.swf。 
script :   后台处理程序的相对路径 。默认值:uploadify.php 
checkScript :用来判断上传选择的文件在服务器是否存在的后台处理程序的相对路径 
fileDataName :设置一个名字,在服务器处理程序中根据该名字来取上传文件的数据。默认为Filedata 
method : 提交方式Post 或Get 默认为Post 
scriptAccess :flash脚本文件的访问模式,如果在本地测试设置为always,默认值:sameDomain  
folder :  上传文件存放的目录 。 
queueID : 文件队列的ID,该ID与存放文件队列的div的ID一致。 
queueSizeLimit : 当允许多文件生成时,设置选择文件的个数,默认值:999 。 
multi : 设置为true时可以上传多个文件。 
auto : 设置为true当选择文件后就直接上传了,为false需要点击上传按钮才上传 。

fileExt : 设置可以选择的文件的类型,格式如:'*.jpg;*.gif,*.png' 。

fileDesc : 这个属性值必须设置fileExt属性后才有效,用来设置选择文件对话框中的提示文本,如设置fileDesc为“请选择图像文件”,
sizeLimit : 上传文件的大小限制 。 
simUploadLimit : 允许同时上传的个数 默认值:1 。 
buttonText : 浏览按钮的文本,默认值:BROWSE 。 
buttonImg : 浏览按钮的图片的路径 。 
hideButton : 设置为true则隐藏浏览按钮的图片 。 
rollover : 值为true和false,设置为true时当鼠标移到浏览按钮上时有反转效果。 
width : 设置浏览按钮的宽度 ,默认值:110。 
height : 设置浏览按钮的高度 ,默认值:30。 
wmode : 设置该项为transparent 可以使浏览按钮的flash背景文件透明,并且flash文件会被置为页面的最高层。 默认值:opaque 。 
cancelImg :选择文件到文件队列中后的每一个文件上的关闭按钮图标

结构图

aaarticlea/png;base64,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" alt="" />

HTML代码

文件上传~Uploadify上传控件
<div>
<div class="inputDiv fl">
<input type="text" name="ImagePath" id="ImagePath" style="width: 600px;">
<img style="display: none;" />
</div>
<div class="fl" style="position: relative;">
<input id="custom_file_uploadEdu" type="file" class="btn" />
<a href="javascript:$('#custom_file_uploadEdu').uploadifyUpload()">上传</a>|
<a href="javascript:$('#custom_file_uploadEdu').uploadifyClearQueue()">取消上传</a>
</div>
<div id="displayMsg"></div>
</div>
文件上传~Uploadify上传控件

JS代码

文件上传~Uploadify上传控件
<script type="text/ecmascript">

    $("#custom_file_uploadEdu").uploadify({
'uploader': '/Scripts/Uploadify/uploadify.swf',
'script': '/ashx/UploadFile.ashx',
'cancelImg': '/Scripts/Uploadify/uploadify-cancel.png',
'folder': '/',
'queueSizeLimit': 1,
'simUploadLimit': 1,
'sizeLimit ': 1024 * 1024 * 5,
'multi': false,
'auto': false,/*如果是自动上传,那上传按钮将没用了*/
'fileExt': '*.jpg;*.gif;*.jpeg;*.mp4',
'fileDesc': '请选择图像或者视频',
'queueID': 'fileQueue',
'width': 110,
'height': 30,
'buttonText': '选择',
'wmode': 'opaque',
'hideButton': false,
'onSelect': function (event, ID, fileObj) {
$("#displayMsg").html("上传中......");
},
'onComplete': function (event, queueId, fileObj, response, data) {
var ary = response.split('|');
if (ary[0] == "0") { //提示错误信息
alert(ary[1]);
}
else {
if (ary[0]=="1") {//上传后的URL
$("#displayMsg").html("上传成功")
$("#ImagePath").attr("value", ary[1]);
$("#ImagePath").remove("img").next("img").show().attr({ "style": "width:50px;height:50px;", "src": ary[1] });
} else {//异常信息
alert(ary[1]);
}
}
}
});
</script>
文件上传~Uploadify上传控件

后台处理程序(接收流,写入流)

文件上传~Uploadify上传控件
namespace WebTest.ashx
{
/// <summary>
/// UploadFile 的摘要说明
/// </summary>
public class UploadFile : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain"; context.Response.Write(new UploadImpl().Upload(context, UpLoadType.ProductImage, false)); } public bool IsReusable
{
get
{
return false;
}
}
} }
文件上传~Uploadify上传控件

UploadImpl类代码

文件上传~Uploadify上传控件
namespace EntityFrameworks.Application.Core.FileUpload
{ /// <summary>
/// 图像上传功能的实现
/// </summary>
public class UploadImpl
{
public UploadImpl(IFileUploadSize fileUploadSize)
{ _fileUploadSize = fileUploadSize ?? new TestFileUploadSize();
}
public UploadImpl()
: this(null)
{ }
#region Fields & Consts
static string FileHostUri = System.Configuration.ConfigurationManager.AppSettings["FileHostUri"]
?? HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority; Point point = new Point(0, 0); //图像从那个坐标点进行截取
double wRate = 1, hRate = 1, setRate = 1;
int newWidth = 0, newHeight = 0;
IFileUploadSize _fileUploadSize;
#endregion #region 图像缩放
/// <summary>
/// 图像的缩放
/// </summary>
/// <param name="file">缩放文件</param>
/// <param name="width">宽</param>
/// <param name="height">高</param>
/// <param name="isEqualScale">是否等比例缩放</param>
/// <param name="name">缩放后存放的地址</param>
/// <returns></returns>
bool CreateThumbnail(HttpPostedFile file, ImageSize imageSize, bool isEqualScale, string name)
{
double width = (double)imageSize.Width;
double height = (double)imageSize.Height; ; try
{
System.Drawing.Image image = System.Drawing.Image.FromStream(file.InputStream);
if (isEqualScale)
{
if (image.Height > height)
{
hRate = height / image.Height;
} if (image.Width > width)
{
wRate = width / image.Width;
} if (wRate != 1 || hRate != 1)
{
if (wRate > hRate)
{
setRate = hRate;
}
else
{
setRate = wRate;
}
} newWidth = (int)(image.Width * setRate);
newHeight = (int)(image.Height * setRate);
if (height > newHeight)
{
point.Y = Convert.ToInt32(height / 2 - newHeight / 2);
}
if (width > newWidth)
{
point.X = Convert.ToInt32(width / 2 - newWidth / 2);
} }
Bitmap bit = new Bitmap((int)(width), (int)(height));
Rectangle r = new Rectangle(point.X, point.Y, (int)(image.Width * setRate), (int)(image.Height * setRate)); Graphics g = Graphics.FromImage(bit);
g.Clear(Color.White);
g.DrawImage(image, r); MemoryStream ms = new MemoryStream();
bit.Save(ms, ImageFormat.Jpeg);
byte[] bytes = ms.ToArray();
string fileName = name + imageSize.ToString();//为缩放图像重新命名
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
stream.Write(bytes, 0, bytes.Length);
}
bit.Dispose();
ms.Dispose();
image.Dispose();
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 图像的等比例缩放,默认文件名不改变,会将原文件覆盖
/// </summary>
/// <param name="file"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
bool CreateThumbnail(HttpPostedFile file, ImageSize imageSize, string name)
{
return CreateThumbnail(file, imageSize, true, name);
}
#endregion public string Upload(HttpContext context, UpLoadType type, bool isScale)
{ ImageSize imageSize = _fileUploadSize.ImageSizeForType[type]; HttpFileCollection files = context.Request.Files; if (files.Count == 0)
{
throw new ArgumentNullException("please choose file for upload.");
} string path = "/upload/" + type.ToString();//相对路径 if (!Directory.Exists(path))
Directory.CreateDirectory(path);
// 只取第 1 个文件
var file = files[0]; if (file != null && file.ContentLength > 0)
{ try
{
string filename = context.Request.Form["fileName"].Split('.')[0]
+ "_"
+ DateTime.Now.ToString("yyyyMMddhhssmm")
+ imageSize.ToString(); // 本地文件系统路径
string savePath = Path.Combine(context.Server.MapPath(path), filename);
file.SaveAs(savePath);
if (isScale)
CreateThumbnail(file, imageSize, savePath); //返回URI路径
string ImageUri = FileHostUri
+ path
+ "/"
+ filename; return "1|" + ImageUri;
}
catch (Exception ex)
{ return "0|" + ex.Message;
} }
return null;
} }
}
文件上传~Uploadify上传控件

效果图

aaarticlea/png;base64,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" alt="" />