C#: 实现支持断点续传多线程下载

/* .Net/C#:  实现支持断点续传多线程下载的  Http Web  客户端工具类  (C# DIY HttpWebClient)
* Reflector  了一下  System.Net.WebClient , 改写或增加了若干 :
* DownLoad Upload  相关方法 !
* DownLoad  相关改动较大 !
增加了  DataReceive ExceptionOccurrs  事件 !
了解服务器端与客户端交互的  HTTP  协议参阅 :
使文件下载的自定义连接支持  FlashGet  的断点续传多线程链接下载 ! JSP/Servlet  实现 !
* http://blog.csdn.net/playyuer/archive/2004/08/02/58430.aspx
使文件下载的自定义连接支持  FlashGet  的断点续传多线程链接下载 ! C#/ASP.Net  实现 !
* http://blog.csdn.net/playyuer/archive/2004/08/02/58281.aspx
*/
//2005-03-14  修订 :
/* .Net/C#:  实现支持断点续传多线程下载的工具类
* Reflector  了一下  System.Net.WebClient , 改写或增加了若干 :
* DownLoad Upload  相关方法 !
增加了  DataReceive ExceptionOccurrs  事件
*/
namespace  Microshaoft . Utils
{
using  System ;
using  System .IO ;
using  System .Net ;
using  System . Text ;
using  System .Security ;
using  System .Threading ;
using  System .Collections.Specialized ;
/// <summary>
///  记录下载的字节位置
/// </summary>
public class  DownLoadState
{
private string  _FileName;
private string  _AttachmentName;
private int  _Position;
private string  _RequestURL;
private string  _ResponseURL;
private int  _Length;
private byte []  _Data;
public string  FileName
{
get
{
return  _FileName;
}
}
public int  Position
{
get
{
return  _Position;
}
}
public int  Length
{
get
{
return  _Length;
}
}
public string  AttachmentName
{
get
{
return  _AttachmentName;
}
}
public string  RequestURL
{
get
{
return  _RequestURL;
}
}
public string  ResponseURL
{
get
{
return  _ResponseURL;
}
}
public byte []  Data
{
get
{
return  _Data;
}
}
internal  DownLoadState ( string  RequestURL,  string  ResponseURL,  string  FileName string AttachmentName,  int  Position int  Length byte []  Data )
{
this . _FileName  FileName ;
this . _RequestURL  RequestURL;
this . _ResponseURL  ResponseURL;
this . _AttachmentName  AttachmentName;
this . _Position  Position ;
this . _Data  Data ;
this . _Length  Length ;
}
internal  DownLoadState ( string  RequestURL,  string  ResponseURL,  string  FileName string AttachmentName,  int  Position int  Length , ThreadCallbackHandler tch )
{
this . _RequestURL  RequestURL;
this . _ResponseURL  ResponseURL;
this . _FileName  FileName ;
this . _AttachmentName  AttachmentName;
this . _Position  Position ;
this . _Length  Length ;
this . _ThreadCallback  tch;
}
internal  DownLoadState ( string  RequestURL,  string  ResponseURL,  string  FileName string AttachmentName,  int  Position int  Length )
{
this . _RequestURL  RequestURL;
this . _ResponseURL  ResponseURL;
this . _FileName  FileName ;
this . _AttachmentName  AttachmentName;
this . _Position  Position ;
this . _Length  Length ;
}
private  ThreadCallbackHandler _ThreadCallback;
public  HttpWebClient httpWebClient
{
get
{
return this . _hwc;
}
set
{
this . _hwc  = value ;
}
}
internal  Thread  thread
{
get
{
return  _thread;
}
set
{
_thread  = value ;
}
}
private  HttpWebClient _hwc;
private  Thread  _thread;
//
internal void  StartDownloadFileChunk ()
{
if  ( this . _ThreadCallback  != null)
{
this . _ThreadCallback ( this . _RequestURL,  this . _FileName,  this . _Position,  this . _Length ) ;
this . _hwc . OnThreadProcess ( this . _thread ) ;
}
}
}
// 委托代理线程的所执行的方法签名一致
public delegate void  ThreadCallbackHandler ( string  S string  s,  int  I int  i ) ;
// 异常处理动作
public enum  ExceptionActions
{
Throw ,
CancelAll,
Ignore ,
Retry
}
/// <summary>
///  包含  Exception  事件数据的类
/// </summary>
public class  ExceptionEventArgs  System . EventArgs
{
private  System . Exception  _Exception ;
private  ExceptionActions _ExceptionAction;
private  DownLoadState _DownloadState;
public  DownLoadState DownloadState
{
get
{
return  _DownloadState;
}
}
public  Exception Exception
{
get
{
return  _Exception ;
}
}
public  ExceptionActions ExceptionAction
{
get
{
return  _ExceptionAction;
}
set
{
_ExceptionAction  = value ;
}
}
internal  ExceptionEventArgs ( System . Exception  e, DownLoadState DownloadState )
{
this ._Exception =  e;
this . _DownloadState  DownloadState;
}
}
/// <summary>
///  包含  DownLoad  事件数据的类
/// </summary>
public class  DownLoadEventArgs  System . EventArgs
{
private  DownLoadState _DownloadState;
public  DownLoadState DownloadState
{
get
{
return  _DownloadState;
}
}
public  DownLoadEventArgs ( DownLoadState DownloadState )
{
this . _DownloadState  DownloadState;
}
}
public class  ThreadProcessEventArgs  System . EventArgs
{
private  Thread  _thread;
public  Thread  thread
{
get
{
return this . _thread;
}
}
public  ThreadProcessEventArgs ( Thread  thread )
{
this . _thread  thread;
}
}
/// <summary>
///  支持断点续传多线程下载的类
/// </summary>
public class  HttpWebClient
{
private static object  _SyncLockObject  = new  object () ;
public delegate void  DataReceiveEventHandler ( HttpWebClient  Sender , DownLoadEventArgs e ) ;
public event  DataReceiveEventHandler DataReceive;  // 接收字节数据事件
public delegate void  ExceptionEventHandler ( HttpWebClient  Sender , ExceptionEventArgs e ) ;
public event  ExceptionEventHandler ExceptionOccurrs;  // 发生异常事件
public delegate void  ThreadProcessEventHandler ( HttpWebClient  Sender , ThreadProcessEventArgs e ) ;
public event  ThreadProcessEventHandler ThreadProcessEnd;  // 发生多线程处理完毕事件
private int  _FileLength;  // 下载文件的总大小
public int  FileLength
{
get
{
return  _FileLength;
}
}
/// <summary>
///  分块下载文件
/// </summary>
/// <param name="Address">URL  地址 </param>
/// <param name="FileName"> 保存到本地的路径文件名 </param>
/// <param name="ChunksCount"> 块数 , 线程数 </param>
public void  DownloadFile ( string  Address string  FileName int  ChunksCount )
{
int  0;  // position
int  0;  // chunk size
string  = null ;
HttpWebRequest  hwrq;
HttpWebResponse  hwrp  = null ;
try
{
hwrq  = ( HttpWebRequest WebRequest . Create ( this . GetUri ( Address )) ;
hwrp  = ( HttpWebResponse hwrq . GetResponse () ;
long  L =  hwrp . ContentLength ;
hwrq . Credentials  this . m_credentials;
L = ((L == - 1 ) || (L >  0x7fffffff )) ? (( long 0x7fffffff ) : L //Int32.MaxValue  该常数的值为  2,147,483,647; 即十六进制的  0x7FFFFFFF
int  = ( int ) L ;
this . _FileLength  l;
//  在本地预定空间 ( 竟然在多线程下不用先预定空间 )
// FileStream sw = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
// sw.Write(new byte[l], 0, l);
// sw.Close();
// sw = null;
bool  = ( hwrp . Headers [ "Accept-Ranges" ] != null &  hwrp . Headers [ "Accept-Ranges" ] ==  "bytes" ) ;
hwrp . Headers [ "Content-Disposition" ] //attachment
if  ( != null)
{
a . Substring ( a . LastIndexOf ( "filename=" ) +  9 ) ;
}
else
{
FileName ;
}
int  ss  s;
if  ( b )
{
ChunksCount;
if  ( 64  1024 // 块大小至少为  128 K  字节
{
64  1024;
}
ss  s;
int  0;
while  ( s )
{
-=  s;
if  ( s )
{
+=  l;
}
if  ( i ++ >  0 )
{
DownLoadState x  = new  DownLoadState ( Address , hwrp . ResponseUri . AbsolutePath FileName , a, p, s, new  ThreadCallbackHandler ( this . DownloadFileChunk )) ;
//  单线程下载
// x.StartDownloadFileChunk();
x . httpWebClient  this ;
// 多线程下载
Thread  = new  Thread (new  ThreadStart ( x . StartDownloadFileChunk )) ;
//this.OnThreadProcess(t);
t . Start () ;
}
+=  s;
}
ss;
byte []  buffer  this . ResponseAsBytes ( Address , hwrp, s,  FileName ) ;
this . OnThreadProcess ( Thread . CurrentThread ) ;
// lock (_SyncLockObject)
// {
// this._Bytes += buffer.Length;
// }
}
}
catch  ( Exception  e )
{
ExceptionActions ea  ExceptionActions .Throw ;
if  ( this . ExceptionOccurrs  != null)
{
DownLoadState x  = new  DownLoadState ( Address , hwrp . ResponseUri . AbsolutePath FileName , a, p, s ) ;
ExceptionEventArgs eea  = new  ExceptionEventArgs ( e, x ) ;
ExceptionOccurrs ( this , eea ) ;
ea  eea . ExceptionAction;
}
if  ( ea  ==  ExceptionActions .Throw)
{
if  (!( is  WebException ) && !( is  SecurityException ))
{
throw  new  WebException ( "net_webclient" , e ) ;
}
throw ;
}
}
}
internal void  OnThreadProcess ( Thread  t )
{
if  ( ThreadProcessEnd  != null)
{
ThreadProcessEventArgs tpea  = new  ThreadProcessEventArgs ( t ) ;
ThreadProcessEnd ( this , tpea ) ;
}
}
/// <summary>
///  下载一个文件块 , 利用该方法可自行实现多线程断点续传
/// </summary>
/// <param name="Address">URL  地址 </param>
/// <param name="FileName"> 保存到本地的路径文件名 </param>
/// <param name="Length"> 块大小 </param>
public void  DownloadFileChunk ( string  Address string  FileName int  FromPosition,  int  Length )
{
HttpWebResponse  hwrp  = null ;
string  = null ;
try
{
//this._FileName = FileName;
HttpWebRequest  hwrq  = ( HttpWebRequest WebRequest . Create ( this . GetUri ( Address )) ;
//hwrq.Credentials = this.m_credentials;
hwrq . AddRange ( FromPosition ) ;
hwrp  = ( HttpWebResponse hwrq . GetResponse () ;
hwrp . Headers [ "Content-Disposition" ] //attachment
if  ( != null)
{
a . Substring ( a . LastIndexOf ( "filename=" ) +  9 ) ;
}
else
{
FileName ;
}
byte []  buffer  this . ResponseAsBytes ( Address , hwrp,  Length FileName ) ;
// lock (_SyncLockObject)
// {
// this._Bytes += buffer.Length;
// }
}
catch  ( Exception  e )
{
ExceptionActions ea  ExceptionActions .Throw ;
if  ( this . ExceptionOccurrs  != null)
{
DownLoadState x  = new  DownLoadState ( Address , hwrp . ResponseUri . AbsolutePath FileName , a, FromPosition,  Length ) ;
ExceptionEventArgs eea  = new  ExceptionEventArgs ( e, x ) ;
ExceptionOccurrs ( this , eea ) ;
ea  eea . ExceptionAction;
}
if  ( ea  ==  ExceptionActions .Throw)
{
if  (!( is  WebException ) && !( is  SecurityException ))
{
throw  new  WebException ( "net_webclient" , e ) ;
}
throw ;
}
}
}
internal byte []  ResponseAsBytes ( string  RequestURL,  WebResponse  Response long  Length string FileName )
{
string  = null //AttachmentName
int  P =  0;  // 整个文件的位置指针
int  num2  0;
try
{
Response . Headers [ "Content-Disposition" ] //attachment
if  ( != null)
{
a . Substring ( a . LastIndexOf ( "filename=" ) +  9 ) ;
}
long  num1  Length //Response.ContentLength;
bool  flag1  false ;
if  ( num1  == - 1 )
{
flag1  true ;
num1  0x10000;  //64k
}
byte []  buffer1  = new  byte [( int num1 ] ;
int  0;  // 本块的位置指针
string  Response . Headers [ "Content-Range" ] ;
if  ( != null)
{
s . Replace ( "bytes " "" ) ;
s . Substring ( 0, s . IndexOf ( "-" )) ;
P =  Convert . ToInt32 ( s ) ;
}
int  num3  0;
Stream  S =  Response . GetResponseStream () ;
do
{
num2  = S. Read ( buffer1, num3,  (( int num1 ) -  num3 ) ;
num3  +=  num2;
if  ( flag1  && ( num3  ==  num1 ))
{
num1  +=  0x10000;
byte []  buffer2  = new  byte [( int num1 ] ;
Buffer . BlockCopy ( buffer1, 0, buffer2, 0, num3 ) ;
buffer1  buffer2;
}
// lock (_SyncLockObject)
// {
// this._bytes += num2;
// }
if  ( num2  0 )
{
if  ( this . DataReceive  != null)
{
byte []  buffer  = new  byte [ num2 ] ;
Buffer . BlockCopy ( buffer1, p, buffer, 0, buffer . Length ) ;
DownLoadState dls  = new  DownLoadState ( RequestURL,  Response . ResponseUri . AbsolutePath FileName , a,  P , num2, buffer ) ;
DownLoadEventArgs dlea  = new  DownLoadEventArgs ( dls ) ;
// 触发事件
this . OnDataReceive ( dlea ) ;
//System.Threading.Thread.Sleep(100);
}
+=  num2;  // 本块的位置指针
P +=  num2;  // 整个文件的位置指针
}
else
{
break ;
}
}
while  ( num2  !=  0 ) ;
S. Close () ;
S = null ;
if  ( flag1 )
{
byte []  buffer3  = new  byte [ num3 ] ;
Buffer . BlockCopy ( buffer1, 0, buffer3, 0, num3 ) ;
buffer1  buffer3;
}
return  buffer1;
}
catch  ( Exception  e )
{
ExceptionActions ea  ExceptionActions .Throw ;
if  ( this . ExceptionOccurrs  != null)
{
DownLoadState x  = new  DownLoadState ( RequestURL,  Response . ResponseUri . AbsolutePath FileName , a,  P , num2 ) ;
ExceptionEventArgs eea  = new  ExceptionEventArgs ( e, x ) ;
ExceptionOccurrs ( this , eea ) ;
ea  eea . ExceptionAction;
}
if  ( ea  ==  ExceptionActions .Throw)
{
if  (!( is  WebException ) && !( is  SecurityException ))
{
throw  new  WebException ( "net_webclient" , e ) ;
}
throw ;
}
return  null ;
}
}
private void  OnDataReceive ( DownLoadEventArgs e )
{
// 触发数据到达事件
DataReceive ( this , e ) ;
}
public byte []  UploadFile ( string  address,  string  fileName )
{
return this . UploadFile ( address,  "POST" , fileName,  "file" ) ;
}
public string  UploadFileEx ( string  address,  string  method,  string  fileName,  string  fieldName )
{
return  Encoding . ASCII . GetString ( UploadFile ( address, method, fileName, fieldName )) ;
}
public byte []  UploadFile ( string  address,  string  method,  string  fileName,  string  fieldName )
{
byte []  buffer4;
FileStream  stream1  = null ;
try
{
fileName  Path . GetFullPath ( fileName ) ;
string  text1  "---------------------"  DateTime . Now . Ticks . ToString ( "x" ) ;
string  text2  "application/octet-stream" ;
stream1  = new  FileStream ( fileName,  FileMode. Open FileAccess. Read ) ;
WebRequest  request1  WebRequest . Create ( this . GetUri ( address )) ;
request1 . Credentials  this . m_credentials;
request1 . ContentType  "multipart/form-data; boundary="  text1;
request1 . Method  method;
string []  textArray1  = new  string [ 7 ] { "--" , text1,  "\r\nContent-Disposition: form-data; name=\""  + fieldName  "\"; filename=\"" Path . GetFileName ( fileName ) "\"\r\nContent-Type: " , text2,  "\r\n\r\n" } ;
string  text3  string . Concat ( textArray1 ) ;
byte []  buffer1  Encoding . UTF8 . GetBytes ( text3 ) ;
byte []  buffer2  Encoding . ASCII . GetBytes ( "\r\n--"  text1  "\r\n" ) ;
long  num1  0x7fffffffffffffff;
try
{
num1  stream1 . Length ;
request1 . ContentLength  = ( num1  buffer1 . Length ) +  buffer2 . Length ;
}
catch
{
}
byte []  buffer3  = new  byte [ Math . Min ( 0x2000,  ( int num1 )] ;
using  ( Stream  stream2  request1 . GetRequestStream ())
{
int  num2;
stream2 . Write ( buffer1, 0, buffer1 . Length ) ;
do
{
num2  stream1 . Read ( buffer3, 0, buffer3 . Length ) ;
if  ( num2  !=  0 )
{
stream2 . Write ( buffer3, 0, num2 ) ;
}
}
while  ( num2  !=  0 ) ;
stream2 . Write ( buffer2, 0, buffer2 . Length ) ;
}
stream1 . Close () ;
stream1  = null ;
WebResponse  response1  request1 . GetResponse () ;
buffer4  this . ResponseAsBytes ( response1 ) ;
}
catch  ( Exception  exception1 )
{
if  ( stream1  != null)
{
stream1 . Close () ;
stream1  = null ;
}
if  (!( exception1  is  WebException ) && !( exception1  is  SecurityException ))
{
//throw new WebException(SR.GetString("net_webclient"), exception1);
throw  new  WebException ( "net_webclient" , exception1 ) ;
}
throw ;
}
return  buffer4;
}
private byte []  ResponseAsBytes ( WebResponse  response )
{
int  num2;
long  num1  response . ContentLength ;
bool  flag1  false ;
if  ( num1  == - 1 )
{
flag1  true ;
num1  0x10000;
}
byte []  buffer1  = new  byte [( int num1 ] ;
Stream  stream1  response . GetResponseStream () ;
int  num3  0;
do
{
num2  stream1 . Read ( buffer1, num3,  (( int num1 ) -  num3 ) ;
num3  +=  num2;
if  ( flag1  && ( num3  ==  num1 ))
{
num1  +=  0x10000;
byte []  buffer2  = new  byte [( int num1 ] ;
Buffer . BlockCopy ( buffer1, 0, buffer2, 0, num3 ) ;
buffer1  buffer2;
}
}
while  ( num2  !=  0 ) ;
stream1 . Close () ;
if  ( flag1 )
{
byte []  buffer3  = new  byte [ num3 ] ;
Buffer . BlockCopy ( buffer1, 0, buffer3, 0, num3 ) ;
buffer1  buffer3;
}
return  buffer1;
}
private  NameValueCollection  m_requestParameters;
private  Uri  m_baseAddress;
private  ICredentials  m_credentials  CredentialCache . DefaultCredentials ;
public  ICredentials  Credentials
{
get
{
return this . m_credentials;
}
set
{
this . m_credentials  = value ;
}
}
public  NameValueCollection  QueryString
{
get
{
if  ( this . m_requestParameters  == null)
{
this . m_requestParameters  = new  NameValueCollection () ;
}
return this . m_requestParameters;
}
set
{
this . m_requestParameters  = value ;
}
}
public string  BaseAddress
{
get
{
if  ( this . m_baseAddress  != null)
{
return this . m_baseAddress . ToString () ;
}
return string . Empty ;
}
set
{
if  ((value == null) || (value. Length  ==  0 ))
{
this . m_baseAddress  = null ;
}
else
{
try
{
this . m_baseAddress  = new  Uri (value) ;
}
catch  ( Exception  exception1 )
{
throw  new  ArgumentException ( "value" , exception1 ) ;
}
}
}
}
private  Uri  GetUri ( string  path )
{
Uri  uri1;
try
{
if  ( this . m_baseAddress  != null)
{
uri1  = new  Uri ( this . m_baseAddress, path ) ;
}
else
{
uri1  = new  Uri ( path ) ;
}
if  ( this . m_requestParameters  == null)
{
return  uri1;
}
StringBuilder  builder1  = new  StringBuilder () ;
string  text1  string . Empty ;
for  ( int  num1  0; num1  this . m_requestParameters . Count ; num1 ++)
{
builder1 . Append ( text1  this . m_requestParameters . AllKeys [ num1 ] +  "="  + this . m_requestParameters [ num1 ]) ;
text1  "&" ;
}
UriBuilder  builder2  = new  UriBuilder ( uri1 ) ;
builder2 . Query  builder1 . ToString () ;
uri1  builder2 . Uri ;
}
catch  ( UriFormatException )
{
uri1  = new  Uri ( Path . GetFullPath ( path )) ;
}
return  uri1;
}
}
}
/// <summary>
///  测试类
/// </summary>
class  AppTest
{
int  _k  0;
int  _K  0;
static void  Main ()
{
AppTest a  = new  AppTest () ;
Microshaoft . Utils . HttpWebClient x  = new  Microshaoft . Utils . HttpWebClient () ;
a . _K  10;
// 订阅  DataReceive  事件
x . DataReceive  += new  Microshaoft . Utils . HttpWebClient . DataReceiveEventHandler ( a . x_DataReceive ) ;
// 订阅  ExceptionOccurrs  事件
x . ExceptionOccurrs  += new Microshaoft . Utils . HttpWebClient . ExceptionEventHandler ( a . x_ExceptionOccurrs ) ;
x . ThreadProcessEnd  += new Microshaoft . Utils . HttpWebClient . ThreadProcessEventHandler ( a . x_ThreadProcessEnd ) ;
string  F =  "http://localhost/download/phpMyAdmin-2.6.1-pl2.zip" ;
F =  "http://down6.flashget.com/flashget182cn.exe" ;
a . _F  = F ;
string  = F. Substring (F. LastIndexOf ( "/" ) +  1 ) ;
//(new System.Threading.Thread(new System.Threading.ThreadStart(new ThreadProcessState(F, @"E:\temp\" + f, 10, x).StartThreadProcess))).Start();
x . DownloadFile (F , @ "d:\temp\" + f, a._K);
// x.DownloadFileChunk(F, @"E:\temp\" + f,15,34556);
System . Console . ReadLine () ;
// string uploadfile = "e:\\test_local.rar";
// string str = x.UploadFileEx("http://localhost/phpmyadmin/uploadaction.php", "POST", uploadfile, "file1");
// System.Console.WriteLine(str);
// System.Console.ReadLine();
}
string  bs  "" // 用于记录上次的位数
bool  false ;
private int  0;
private static object  _SyncLockObject  = new  object () ;
string  _F;
string  _f;
private void  x_DataReceive ( Microshaoft . Utils . HttpWebClient  Sender , Microshaoft . Utils . DownLoadEventArgs e )
{
if  (! this . b )
{
lock  ( _SyncLockObject )
{
if  (! this . b )
{
System . Console . Write ( System . DateTime . Now . ToString () +  已接收数据 : " ) ;
//System.Console.Write( System.DateTime.Now.ToString() + "  已接收数据 : ");
this . true ;
}
}
}
string  e . DownloadState . FileName ;
if  ( e . DownloadState . AttachmentName  != null)
System .IO. Path . GetDirectoryName ( f ) +  @ "\" + e.DownloadState.AttachmentName;
this . _f  f;
using  ( System .IO. FileStream  sw  = new  System .IO. FileStream ( f,  System .IO.FileMode.OpenOrCreate , System .IO.FileAccess.ReadWrite System .IO.FileShare.ReadWrite))
{
sw . Position  e . DownloadState . Position ;
sw . Write ( e . DownloadState . Data , 0, e . DownloadState . Data . Length ) ;
sw . Close () ;
}
string  System . DateTime . Now . ToString () ;
lock  ( _SyncLockObject )
{
this . +=  e . DownloadState . Data . Length ;
System . Console . Write ( bs  "\b\b\b\b\b\b\b\b\b\b" " / "  Sender . FileLength  字节数据  "  s ) ;
//System.Console.Write(bs + i + "  字节数据  " + s);
this . bs  = new  string ( '\b' , Digits ( i ) +  Digits ( Sender . FileLength ) +  s . Length ) ;
}
}
int  Digits ( int  n // 数字所占位数
{
System . Math . Abs ( n ) ;
10;
int  1;
while  ( 0 )
{
10;
i ++ ;
}
return  i;
}
private void  x_ExceptionOccurrs ( Microshaoft . Utils . HttpWebClient  Sender , Microshaoft . Utils . ExceptionEventArgs e )
{
System . Console . WriteLine ( e . Exception . Message ) ;
// 发生异常重新下载相当于断点续传 , 你可以自己自行选择处理方式
Microshaoft . Utils . HttpWebClient x  = new  Microshaoft . Utils . HttpWebClient () ;
x . DownloadFileChunk ( this . _F,  this . _f, e . DownloadState . Position , e . DownloadState . Length ) ;
e . ExceptionAction  Microshaoft . Utils . ExceptionActions .Ignore ;
}
private void  x_ThreadProcessEnd ( Microshaoft . Utils . HttpWebClient  Sender , Microshaoft . Utils . ThreadProcessEventArgs e )
{
//if (e.thread.ThreadState == System.Threading.ThreadState.Stopped)
if  ( this . _k  ++ ==  this . _K  1 )
System . Console . WriteLine ( "\nend" ) ;
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值