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.length - retNum;
                        
                        
// 判断剩余情况
                         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版本,还在继续修改当中。

效果图:

源码:断点续传Server.rar  客户端


 

转载于:https://www.cnblogs.com/tzy080112/archive/2011/09/06/2169173.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值