[转载]FLEX+Webservice 大附件上传、断点续传实现

转载FLEX+Webservice 大附件上传、断点续传实现 – 大侠酷裤马路 – 博客园.

最近项目需要,面临大附件上传的功能,具体研究如下:
实现思路
大附件上传,如何流畅不占用内存,还要支持断点续传,当第一次看到这 些需求的时候还是有所顾虑,传统ASP.NET中利用fileupload可以实现上传,但是webconfig中文件大小受限制,即使设置大小了也将面 临超时的问题。对于上述情况,WINFORM应该能够很好的解决断点续传大文件,当应用到WEB应用中的时候就很难如此轻松了,因此富客户端思想是很好的 选择,决定采用FLEX实现客户端,Webservice实现客户端。
由于ASP.NET默认支持4M大小文件上传,一次需要将需要上传的文件进行分割,客户端分块上传,服务端分块追加。
具体实现
1)、客户端实现

客户端界面设计

<s:Group width=”100%” height=”100%”>
<s:Button id=”btnBrower” x=”390″ y=”25″ label=”浏览…” width=”60″ click=”btnBrower_clickHandler(event)”></s:Button>
<s:TextInput id=”edFile” x=”21″ y=”24″ width=”361″ enabled=”false”/>
<s:Button id=”btnUpload” x=”458″ y=”25″ label=”开始上传” width=”71″ click=”btnUpload_clickHandler(event)”/>
<mx:Canvas width=”508″ height=”25″ backgroundColor=”0Xf1f1f1″ x=”21″ y=”53″ borderStyle=”solid” borderColor=”0Xbbbbbb”>
<mx:Label text=”” fontWeight=”bold” id=”tip_txt” x=”5″ y=”4″/>
</mx:Canvas>
<mx:Canvas id=”totalProcess” borderStyle=”solid” x=”22″ width=”507″ y=”82″ height=”13″ borderColor=”0X124fc0″ backgroundColor=”0xffffff”>
<mx:Canvas backgroundColor=”0X124fc0″ backgroundAlpha=”0.5″ id=”processBar_Total” width=”0″ height=”23″/>
</mx:Canvas>

</s:Group>

定义Webservice方法,对应服务端,各自有自己的返回事件

<s:WebService id=service wsdl=../Service.asmx?wsdl useProxy=false>
<s:operation name=WriteFile result=onResult(event) fault=onFault(event)>
</s:operation>
<s:operation name=CheckFile result=onCheckResult(event) fault=onCheckFault(event)>
</s:operation>
<s:operation name=CopyFile result=onCopyResult(event) fault=onCopyFault(event)>
</s:operation>
</s:WebService>

浏览需要上传的文件

//页面加载完毕,进行相关事件注册
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
// 注册调用js函数
ExternalInterface.addCallback(getFileInfo,GetFileInfo);

//初始化文件浏览事件
file.addEventListener(Event.SELECT,onSelect);//选择文件事件
file.addEventListener(Event.COMPLETE,onComplete);//文件加载完毕
file.addEventListener(Event.OPEN,onOpen);
btnUpload.enabled
=false;
}

//浏览文件
private function onSelect(evt:Event):void
{
this.tip_txt.text=“”;
edFile.text
=file.name;
//浏览完成,开始加载
file.load();
}
//加载文件完毕
private function onComplete(evt:Event):void
{
this.tip_txt.text=加载完毕;
btnUpload.enabled
=true;
}

private function onOpen(evt:Event):void
{
this.tip_txt.text=正在加载…;
}

校验服务端文件是否存在,不存在则创建,存在则判断是否需要断点续传

//校验文件函数
private function CheckFile():void
{
//调用webservice方法,传递文件名进行校验
service.CheckFile.send(file.name);
}
//webervice,校验成功
private function onCheckResult(event:ResultEvent):void
{
//获取返回值
var retArray:Array=new Array();
retArray
=event.result.toString().split(,);
var retMsg:String=retArray[0].toString();//返回文件存在与否消息
var retNum:int=int(retArray[1].toString());//返回文件大小
tip_txt.text=retMsg;

//判断是否存在文件
if(retNum != 0)
{
//若文件已经存在,判断文件是否已经上传完毕
if(retNum == file.data.length)
tip_txt.text
=文件已上传完毕;
else
{
tip_txt.text
=准备断点续传;

//断点续传需要重新计算块数,剩余大小
var Leave:int= file.data.lengthretNum;

//判断剩余情况
if(Leave>blocksize)
{
//剩余部分分块
var BlockNum2:Number=(Leave / blocksize);
BlockNum
=int(BlockNum2);
BlockNumles
=int(BlockNum2);
reBlock
=Leave % blocksize;
tip_txt.text
=正在处理…;
//调用上传函数
uploadFile(retNum,blocksize);
}
else
{
//直接从返回值大小开始,传递剩余部分
BlockNumles=1;
uploadFile(retNum,reBlock);
}
}
}
else
{
//若文件不存在,则创建,从0开始
var BlockNum1:Number=(file.data.length / blocksize);
BlockNum
=int(BlockNum1);
BlockNumles
=int(BlockNum1);
reBlock
=file.data.length % blocksize;

tip_txt.text=正在处理…;
uploadFile(retNum,blocksize);
}
}

private function onCheckFault(event:FaultEvent):void
{
Alert.show(event.toString());
}

开始上传

//上传附件函数
private function uploadFile(begin:int,end:int):void
{
//判断文件大小
if(file.data.length>blocksize)
{
//读取部分文件,分块上传
fileUpload.writeBytes(file.data,begin,end);
service.WriteFile.send(file.name,fileUpload);
}
else
{
//直接上传
service.WriteFile.send(file.name,fileUpload);
}
}

//webservice相关事件函数,上传成功
private function onResult(event:ResultEvent):void
{
//每次上传成功返回值,作为下次传递的开始位置
var begin:int=int(event.result.toString());
BlockNumles
-=1;//递减
BlockNumadd+=1;//递增
//清空历史数据
fileUpload.clear();

//进度条
onProgress(begin,file.data.length);
//判断剩余块多少,进行不同情况的上传
if(BlockNumles>0)
{
uploadFile(begin,blocksize);
}

if(BlockNumles==0)
{
uploadFile(begin,file.data.length
begin);
tip_txt.text
=上传完毕!;
tip_txt.text
=开始扫描文件…;
service.CopyFile.send(file.name);
}
}
//上传失败
private function onFault(event:FaultEvent):void
{
Alert.show(
event.toString());
}

进度监视

//上传进度条
private function onProgress(Loaded:int,Total:int):void
{
processBar_Total.width
=(Loaded/Total)*506;
tip_txt.text
=已上传: + Loaded+/+Total;
if(Loaded==Total)
tip_txt.text
=已上传完毕;
}

上传完毕处理文件,完毕之后需要对文件进行类似处理,在这里是对文件进行重命名。具体在客户端可以体现出来

//复制文件
private function onCopyResult(event:ResultEvent):void
{
tip_txt.text
=扫描完成;
//文件上传结束,调用js函数
var f:String = showButton;
var m:String
= ExternalInterface.call(f);
trace(m);
}

private function onCopyFault(event:FaultEvent):void
{
Alert.show(
event.toString());
}

2)、服务端实现
对应客户端三个方法实现,分别是校验、上传、上传完毕
校验文件,并返回值

#region 校验文件是否存在
[WebMethod]
public string CheckFile(string FileName)
{
string FileSavePath = Server.MapPath(File/) + FileName;
if (!IsExistFile(FileSavePath))
return 文件不存在,0;
else
{
string FileSize = GetFileSize(FileSavePath).ToString();
return 文件已存在, + FileSize;
}
}
#endregion

开始写文件,没有则创建,有则追加

#region 写文件
[WebMethod]
public string WriteFile(string FileName, byte[] filestrem)
{
string FileSavePath = Server.MapPath(File/) + FileName + .temp;
if (!IsExistFile(FileSavePath))
{
FileStream fs
= new FileStream(FileSavePath, FileMode.Create);
//获得字节数组
byte[] data = filestrem;
//开始写入
fs.Write(data, 0, data.Length);
//清空缓冲区、关闭流
fs.Flush();
fs.Close();
}
else
{
//追加文件
using (System.IO.FileStream f = new System.IO.FileStream(FileSavePath, System.IO.FileMode.Append, FileAccess.Write))
{
byte[] b = filestrem;
f.Write(b,
0, b.Length);
}
}

return GetFileSize(FileSavePath).ToString();
}
#endregion

上传完毕

#region
[WebMethod]
public string CopyFile(string FileName)
{
string FileSavePath = Server.MapPath(File/) + FileName+.temp;
string FileConvertPath = Server.MapPath(ConvertFile/) + FileName;

//如果目标中存在同名文件,则删除
if (IsExistFile(FileConvertPath))
{
DeleteFile(FileConvertPath);
}
//将文件复制到指定目录
File.Copy(FileSavePath, FileConvertPath);

//删除原始临时文件
DeleteFile(FileSavePath);

string Path = FileConvertPath;
return Path;
}
#endregion

存在问题
客户端要把文件读取完毕之后,才开始分段上传,如果文件过大,内存玩儿不转那么浏览器将会死掉。需要继续改进,请大家拍 砖!!源代码全部奉上,了解flex的可以看看flex部分源码,不了解的可以直接在项目中使用,已经在.NET项目中配置完毕,可直接运行看到效果。本 例子仅为beta1.0版本,还在继续修改当中。

效果图:

源码:断点续传.rar

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏