1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Net; 5 using System.IO; 6 using System.Globalization; 7 using System.Text.RegularExpressions; 8 9 namespace TPVAOC.Net 10 { 11 /// <summary> 12 /// FTP处理操作类 13 /// 功能: 14 /// 下载文件 15 /// 上传文件 16 /// 上传文件的进度信息 17 /// 下载文件的进度信息 18 /// 删除文件 19 /// 列出文件 20 /// 列出目录 21 /// 进入子目录 22 /// 退出当前目录返回上一层目录 23 /// 判断远程文件是否存在 24 /// 判断远程文件是否存在 25 /// 删除远程文件 26 /// 建立目录 27 /// 删除目录 28 /// 文件(目录)改名 29 30 /// </summary> 31 /// <remarks> 32 /// 创建人:南疯 33 /// 创建时间:2007年4月28日 34 /// </remarks> 35 36 #region 文件信息结构 37 public struct FileStruct 38 { 39 public string Flags; 40 public string Owner; 41 public string Group; 42 public bool IsDirectory; 43 public DateTime CreateTime; 44 public string Name; 45 } 46 public enum FileListStyle 47 { 48 UnixStyle, 49 WindowsStyle, 50 Unknown 51 } 52 #endregion 53 public class clsFTP 54 { 55 #region 属性信息 56 /// <summary> 57 /// FTP请求对象 58 /// </summary> 59 FtpWebRequest Request = null; 60 /// <summary> 61 /// FTP响应对象 62 /// </summary> 63 FtpWebResponse Response = null; 64 /// <summary> 65 /// FTP服务器地址 66 /// </summary> 67 private Uri _Uri; 68 /// <summary> 69 /// FTP服务器地址 70 /// </summary> 71 public Uri Uri 72 { 73 get 74 { 75 if (_DirectoryPath == "/") 76 { 77 return _Uri; 78 } 79 else 80 { 81 string strUri = _Uri.ToString(); 82 if (strUri.EndsWith("/")) 83 { 84 strUri = strUri.Substring(0, strUri.Length - 1); 85 } 86 return new Uri(strUri + this.DirectoryPath); 87 } 88 } 89 set 90 { 91 if (value.Scheme != Uri.UriSchemeFtp) 92 { 93 throw new Exception("Ftp 地址格式错误!"); 94 } 95 _Uri = new Uri(value.GetLeftPart(UriPartial.Authority)); 96 _DirectoryPath = value.AbsolutePath; 97 if (!_DirectoryPath.EndsWith("/")) 98 { 99 _DirectoryPath += "/"; 100 } 101 } 102 } 103 104 /// <summary> 105 /// 当前工作目录 106 /// </summary> 107 private string _DirectoryPath; 108 109 /// <summary> 110 /// 当前工作目录 111 /// </summary> 112 public string DirectoryPath 113 { 114 get { return _DirectoryPath; } 115 set { _DirectoryPath = value; } 116 } 117 118 /// <summary> 119 /// FTP登录用户 120 /// </summary> 121 private string _UserName; 122 /// <summary> 123 /// FTP登录用户 124 /// </summary> 125 public string UserName 126 { 127 get { return _UserName; } 128 set { _UserName = value; } 129 } 130 131 /// <summary> 132 /// 错误信息 133 /// </summary> 134 private string _ErrorMsg; 135 /// <summary> 136 /// 错误信息 137 /// </summary> 138 public string ErrorMsg 139 { 140 get { return _ErrorMsg; } 141 set { _ErrorMsg = value; } 142 } 143 144 /// <summary> 145 /// FTP登录密码 146 /// </summary> 147 private string _Password; 148 /// <summary> 149 /// FTP登录密码 150 /// </summary> 151 public string Password 152 { 153 get { return _Password; } 154 set { _Password = value; } 155 } 156 157 /// <summary> 158 /// 连接FTP服务器的代理服务 159 /// </summary> 160 private WebProxy _Proxy = null; 161 /// <summary> 162 /// 连接FTP服务器的代理服务 163 /// </summary> 164 public WebProxy Proxy 165 { 166 get 167 { 168 return _Proxy; 169 } 170 set 171 { 172 _Proxy = value; 173 } 174 } 175 176 /// <summary> 177 /// 是否需要删除临时文件 178 /// </summary> 179 private bool _isDeleteTempFile = false; 180 /// <summary> 181 /// 异步上传所临时生成的文件 182 /// </summary> 183 private string _UploadTempFile = ""; 184 #endregion 185 #region 事件 186 public delegate void De_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e); 187 public delegate void De_DownloadDataCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e); 188 public delegate void De_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e); 189 public delegate void De_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e); 190 191 /// <summary> 192 /// 异步下载进度发生改变触发的事件 193 /// </summary> 194 public event De_DownloadProgressChanged DownloadProgressChanged; 195 /// <summary> 196 /// 异步下载文件完成之后触发的事件 197 /// </summary> 198 public event De_DownloadDataCompleted DownloadDataCompleted; 199 /// <summary> 200 /// 异步上传进度发生改变触发的事件 201 /// </summary> 202 public event De_UploadProgressChanged UploadProgressChanged; 203 /// <summary> 204 /// 异步上传文件完成之后触发的事件 205 /// </summary> 206 public event De_UploadFileCompleted UploadFileCompleted; 207 #endregion 208 #region 构造析构函数 209 /// <summary> 210 /// 构造函数 211 /// </summary> 212 /// <param name="FtpUri">FTP地址</param> 213 /// <param name="strUserName">登录用户名</param> 214 /// <param name="strPassword">登录密码</param> 215 public clsFTP(Uri FtpUri, string strUserName, string strPassword) 216 { 217 this._Uri = new Uri(FtpUri.GetLeftPart(UriPartial.Authority)); 218 _DirectoryPath = FtpUri.AbsolutePath; 219 if (!_DirectoryPath.EndsWith("/")) 220 { 221 _DirectoryPath += "/"; 222 } 223 this._UserName = strUserName; 224 this._Password = strPassword; 225 this._Proxy = null; 226 } 227 /// <summary> 228 /// 构造函数 229 /// </summary> 230 /// <param name="FtpUri">FTP地址</param> 231 /// <param name="strUserName">登录用户名</param> 232 /// <param name="strPassword">登录密码</param> 233 /// <param name="objProxy">连接代理</param> 234 public clsFTP(Uri FtpUri, string strUserName, string strPassword, WebProxy objProxy) 235 { 236 this._Uri = new Uri(FtpUri.GetLeftPart(UriPartial.Authority)); 237 _DirectoryPath = FtpUri.AbsolutePath; 238 if (!_DirectoryPath.EndsWith("/")) 239 { 240 _DirectoryPath += "/"; 241 } 242 this._UserName = strUserName; 243 this._Password = strPassword; 244 this._Proxy = objProxy; 245 } 246 /// <summary> 247 /// 构造函数 248 /// </summary> 249 public clsFTP() 250 { 251 this._UserName = "anonymous"; //匿名用户 252 this._Password = "@anonymous"; 253 this._Uri = null; 254 this._Proxy = null; 255 } 256 257 /// <summary> 258 /// 析构函数 259 /// </summary> 260 ~clsFTP() 261 { 262 if (Response != null) 263 { 264 Response.Close(); 265 Response = null; 266 } 267 if (Request != null) 268 { 269 Request.Abort(); 270 Request = null; 271 } 272 } 273 #endregion 274 #region 建立连接 275 /// <summary> 276 /// 建立FTP链接,返回响应对象 277 /// </summary> 278 /// <param name="uri">FTP地址</param> 279 /// <param name="FtpMathod">操作命令</param> 280 private FtpWebResponse Open(Uri uri, string FtpMathod) 281 { 282 try 283 { 284 Request = (FtpWebRequest)WebRequest.Create(uri); 285 Request.Method = FtpMathod; 286 Request.UseBinary = true; 287 Request.Credentials = new NetworkCredential(this.UserName, this.Password); 288 if (this.Proxy != null) 289 { 290 Request.Proxy = this.Proxy; 291 } 292 return (FtpWebResponse)Request.GetResponse(); 293 } 294 catch (Exception ep) 295 { 296 ErrorMsg = ep.ToString(); 297 throw ep; 298 } 299 } 300 /// <summary> 301 /// 建立FTP链接,返回请求对象 302 /// </summary> 303 /// <param name="uri">FTP地址</param> 304 /// <param name="FtpMathod">操作命令</param> 305 private FtpWebRequest OpenRequest(Uri uri, string FtpMathod) 306 { 307 try 308 { 309 Request = (FtpWebRequest)WebRequest.Create(uri); 310 Request.Method = FtpMathod; 311 Request.UseBinary = true; 312 Request.Credentials = new NetworkCredential(this.UserName, this.Password); 313 if (this.Proxy != null) 314 { 315 Request.Proxy = this.Proxy; 316 } 317 return Request; 318 } 319 catch (Exception ep) 320 { 321 ErrorMsg = ep.ToString(); 322 throw ep; 323 } 324 } 325 #endregion 326 #region 下载文件 327 328 /// <summary> 329 /// 从FTP服务器下载文件,使用与远程文件同名的文件名来保存文件 330 /// </summary> 331 /// <param name="RemoteFileName">远程文件名</param> 332 /// <param name="LocalPath">本地路径</param> 333 334 public bool DownloadFile(string RemoteFileName, string LocalPath) 335 { 336 return DownloadFile(RemoteFileName, LocalPath, RemoteFileName); 337 } 338 /// <summary> 339 /// 从FTP服务器下载文件,指定本地路径和本地文件名 340 /// </summary> 341 /// <param name="RemoteFileName">远程文件名</param> 342 /// <param name="LocalPath">本地路径</param> 343 /// <param name="LocalFilePath">保存文件的本地路径,后面带有"\"</param> 344 /// <param name="LocalFileName">保存本地的文件名</param> 345 public bool DownloadFile(string RemoteFileName, string LocalPath, string LocalFileName) 346 { 347 byte[] bt = null; 348 try 349 { 350 if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(LocalFileName) || !IsValidPathChars(LocalPath)) 351 { 352 throw new Exception("非法文件名或目录名!"); 353 } 354 if (!Directory.Exists(LocalPath)) 355 { 356 throw new Exception("本地文件路径不存在!"); 357 } 358 359 string LocalFullPath = Path.Combine(LocalPath, LocalFileName); 360 if (File.Exists(LocalFullPath)) 361 { 362 throw new Exception("当前路径下已经存在同名文件!"); 363 } 364 bt = DownloadFile(RemoteFileName); 365 if (bt != null) 366 { 367 FileStream stream = new FileStream(LocalFullPath, FileMode.Create); 368 stream.Write(bt, 0, bt.Length); 369 stream.Flush(); 370 stream.Close(); 371 return true; 372 } 373 else 374 { 375 return false; 376 } 377 } 378 catch (Exception ep) 379 { 380 ErrorMsg = ep.ToString(); 381 throw ep; 382 } 383 } 384 385 /// <summary> 386 /// 从FTP服务器下载文件,返回文件二进制数据 387 /// </summary> 388 /// <param name="RemoteFileName">远程文件名</param> 389 public byte[] DownloadFile(string RemoteFileName) 390 { 391 try 392 { 393 if (!IsValidFileChars(RemoteFileName)) 394 { 395 throw new Exception("非法文件名或目录名!"); 396 } 397 Response = Open(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.DownloadFile); 398 Stream Reader = Response.GetResponseStream(); 399 400 MemoryStream mem = new MemoryStream(1024 * 500); 401 byte[] buffer = new byte[1024]; 402 int bytesRead = 0; 403 int TotalByteRead = 0; 404 while (true) 405 { 406 bytesRead = Reader.Read(buffer, 0, buffer.Length); 407 TotalByteRead += bytesRead; 408 if (bytesRead == 0) 409 break; 410 mem.Write(buffer, 0, bytesRead); 411 } 412 if (mem.Length > 0) 413 { 414 return mem.ToArray(); 415 } 416 else 417 { 418 return null; 419 } 420 } 421 catch (Exception ep) 422 { 423 ErrorMsg = ep.ToString(); 424 throw ep; 425 } 426 } 427 #endregion 428 #region 异步下载文件 429 /// <summary> 430 /// 从FTP服务器异步下载文件,指定本地路径和本地文件名 431 /// </summary> 432 /// <param name="RemoteFileName">远程文件名</param> 433 /// <param name="LocalPath">保存文件的本地路径,后面带有"\"</param> 434 /// <param name="LocalFileName">保存本地的文件名</param> 435 public void DownloadFileAsync(string RemoteFileName, string LocalPath, string LocalFileName) 436 { 437 byte[] bt = null; 438 try 439 { 440 if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(LocalFileName) || !IsValidPathChars(LocalPath)) 441 { 442 throw new Exception("非法文件名或目录名!"); 443 } 444 if (!Directory.Exists(LocalPath)) 445 { 446 throw new Exception("本地文件路径不存在!"); 447 } 448 449 string LocalFullPath = Path.Combine(LocalPath, LocalFileName); 450 if (File.Exists(LocalFullPath)) 451 { 452 throw new Exception("当前路径下已经存在同名文件!"); 453 } 454 DownloadFileAsync(RemoteFileName, LocalFullPath); 455 456 } 457 catch (Exception ep) 458 { 459 ErrorMsg = ep.ToString(); 460 throw ep; 461 } 462 } 463 464 /// <summary> 465 /// 从FTP服务器异步下载文件,指定本地完整路径文件名 466 /// </summary> 467 /// <param name="RemoteFileName">远程文件名</param> 468 /// <param name="LocalFullPath">本地完整路径文件名</param> 469 public void DownloadFileAsync(string RemoteFileName, string LocalFullPath) 470 { 471 try 472 { 473 if (!IsValidFileChars(RemoteFileName)) 474 { 475 throw new Exception("非法文件名或目录名!"); 476 } 477 if (File.Exists(LocalFullPath)) 478 { 479 throw new Exception("当前路径下已经存在同名文件!"); 480 } 481 MyWebClient client = new MyWebClient(); 482 483 client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged); 484 client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted); 485 client.Credentials = new NetworkCredential(this.UserName, this.Password); 486 if (this.Proxy != null) 487 { 488 client.Proxy = this.Proxy; 489 } 490 client.DownloadFileAsync(new Uri(this.Uri.ToString() + RemoteFileName), LocalFullPath); 491 } 492 catch (Exception ep) 493 { 494 ErrorMsg = ep.ToString(); 495 throw ep; 496 } 497 } 498 499 /// <summary> 500 /// 异步下载文件完成之后触发的事件 501 /// </summary> 502 /// <param name="sender">下载对象</param> 503 /// <param name="e">数据信息对象</param> 504 void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 505 { 506 if (DownloadDataCompleted != null) 507 { 508 DownloadDataCompleted(sender, e); 509 } 510 } 511 512 /// <summary> 513 /// 异步下载进度发生改变触发的事件 514 /// </summary> 515 /// <param name="sender">下载对象</param> 516 /// <param name="e">进度信息对象</param> 517 void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 518 { 519 if (DownloadProgressChanged != null) 520 { 521 DownloadProgressChanged(sender, e); 522 } 523 } 524 #endregion 525 #region 上传文件 526 /// <summary> 527 /// 上传文件到FTP服务器 528 /// </summary> 529 /// <param name="LocalFullPath">本地带有完整路径的文件名</param> 530 public bool UploadFile(string LocalFullPath) 531 { 532 return UploadFile(LocalFullPath, Path.GetFileName(LocalFullPath), false); 533 } 534 /// <summary> 535 /// 上传文件到FTP服务器 536 /// </summary> 537 /// <param name="LocalFullPath">本地带有完整路径的文件</param> 538 /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> 539 public bool UploadFile(string LocalFullPath, bool OverWriteRemoteFile) 540 { 541 return UploadFile(LocalFullPath, Path.GetFileName(LocalFullPath), OverWriteRemoteFile); 542 } 543 /// <summary> 544 /// 上传文件到FTP服务器 545 /// </summary> 546 /// <param name="LocalFullPath">本地带有完整路径的文件</param> 547 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 548 public bool UploadFile(string LocalFullPath, string RemoteFileName) 549 { 550 return UploadFile(LocalFullPath, RemoteFileName, false); 551 } 552 /// <summary> 553 /// 上传文件到FTP服务器 554 /// </summary> 555 /// <param name="LocalFullPath">本地带有完整路径的文件名</param> 556 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 557 /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> 558 public bool UploadFile(string LocalFullPath, string RemoteFileName, bool OverWriteRemoteFile) 559 { 560 try 561 { 562 if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(Path.GetFileName(LocalFullPath)) || !IsValidPathChars(Path.GetDirectoryName(LocalFullPath))) 563 { 564 throw new Exception("非法文件名或目录名!"); 565 } 566 if (File.Exists(LocalFullPath)) 567 { 568 FileStream Stream = new FileStream(LocalFullPath, FileMode.Open, FileAccess.Read); 569 byte[] bt = new byte[Stream.Length]; 570 Stream.Read(bt, 0, (Int32)Stream.Length); //注意,因为Int32的最大限制,最大上传文件只能是大约2G多一点 571 Stream.Close(); 572 return UploadFile(bt, RemoteFileName, OverWriteRemoteFile); 573 } 574 else 575 { 576 throw new Exception("本地文件不存在!"); 577 } 578 } 579 catch (Exception ep) 580 { 581 ErrorMsg = ep.ToString(); 582 throw ep; 583 } 584 } 585 /// <summary> 586 /// 上传文件到FTP服务器 587 /// </summary> 588 /// <param name="FileBytes">上传的二进制数据</param> 589 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 590 public bool UploadFile(byte[] FileBytes, string RemoteFileName) 591 { 592 if (!IsValidFileChars(RemoteFileName)) 593 { 594 throw new Exception("非法文件名或目录名!"); 595 } 596 return UploadFile(FileBytes, RemoteFileName, false); 597 } 598 /// <summary> 599 /// 上传文件到FTP服务器 600 /// </summary> 601 /// <param name="FileBytes">文件二进制内容</param> 602 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 603 /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> 604 public bool UploadFile(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile) 605 { 606 try 607 { 608 if (!IsValidFileChars(RemoteFileName)) 609 { 610 throw new Exception("非法文件名!"); 611 } 612 if (!OverWriteRemoteFile && FileExist(RemoteFileName)) 613 { 614 throw new Exception("FTP服务上面已经存在同名文件!"); 615 } 616 Response = Open(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.UploadFile); 617 Stream requestStream = Request.GetRequestStream(); 618 MemoryStream mem = new MemoryStream(FileBytes); 619 620 byte[] buffer = new byte[1024]; 621 int bytesRead = 0; 622 int TotalRead = 0; 623 while (true) 624 { 625 bytesRead = mem.Read(buffer, 0, buffer.Length); 626 if (bytesRead == 0) 627 break; 628 TotalRead += bytesRead; 629 requestStream.Write(buffer, 0, bytesRead); 630 } 631 requestStream.Close(); 632 Response = (FtpWebResponse)Request.GetResponse(); 633 mem.Close(); 634 mem.Dispose(); 635 FileBytes = null; 636 return true; 637 } 638 catch (Exception ep) 639 { 640 ErrorMsg = ep.ToString(); 641 throw ep; 642 } 643 } 644 #endregion 645 #region 异步上传文件 646 /// <summary> 647 /// 异步上传文件到FTP服务器 648 /// </summary> 649 /// <param name="LocalFullPath">本地带有完整路径的文件名</param> 650 public void UploadFileAsync(string LocalFullPath) 651 { 652 UploadFileAsync(LocalFullPath, Path.GetFileName(LocalFullPath), false); 653 } 654 /// <summary> 655 /// 异步上传文件到FTP服务器 656 /// </summary> 657 /// <param name="LocalFullPath">本地带有完整路径的文件</param> 658 /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> 659 public void UploadFileAsync(string LocalFullPath, bool OverWriteRemoteFile) 660 { 661 UploadFileAsync(LocalFullPath, Path.GetFileName(LocalFullPath), OverWriteRemoteFile); 662 } 663 /// <summary> 664 /// 异步上传文件到FTP服务器 665 /// </summary> 666 /// <param name="LocalFullPath">本地带有完整路径的文件</param> 667 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 668 public void UploadFileAsync(string LocalFullPath, string RemoteFileName) 669 { 670 UploadFileAsync(LocalFullPath, RemoteFileName, false); 671 } 672 /// <summary> 673 /// 异步上传文件到FTP服务器 674 /// </summary> 675 /// <param name="LocalFullPath">本地带有完整路径的文件名</param> 676 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 677 /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> 678 public void UploadFileAsync(string LocalFullPath, string RemoteFileName, bool OverWriteRemoteFile) 679 { 680 try 681 { 682 if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(Path.GetFileName(LocalFullPath)) || !IsValidPathChars(Path.GetDirectoryName(LocalFullPath))) 683 { 684 throw new Exception("非法文件名或目录名!"); 685 } 686 if (!OverWriteRemoteFile && FileExist(RemoteFileName)) 687 { 688 throw new Exception("FTP服务上面已经存在同名文件!"); 689 } 690 if (File.Exists(LocalFullPath)) 691 { 692 MyWebClient client = new MyWebClient(); 693 694 client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged); 695 client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted); 696 client.Credentials = new NetworkCredential(this.UserName, this.Password); 697 if (this.Proxy != null) 698 { 699 client.Proxy = this.Proxy; 700 } 701 client.UploadFileAsync(new Uri(this.Uri.ToString() + RemoteFileName), LocalFullPath); 702 703 } 704 else 705 { 706 throw new Exception("本地文件不存在!"); 707 } 708 } 709 catch (Exception ep) 710 { 711 ErrorMsg = ep.ToString(); 712 throw ep; 713 } 714 } 715 /// <summary> 716 /// 异步上传文件到FTP服务器 717 /// </summary> 718 /// <param name="FileBytes">上传的二进制数据</param> 719 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 720 public void UploadFileAsync(byte[] FileBytes, string RemoteFileName) 721 { 722 if (!IsValidFileChars(RemoteFileName)) 723 { 724 throw new Exception("非法文件名或目录名!"); 725 } 726 UploadFileAsync(FileBytes, RemoteFileName, false); 727 } 728 /// <summary> 729 /// 异步上传文件到FTP服务器 730 /// </summary> 731 /// <param name="FileBytes">文件二进制内容</param> 732 /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> 733 /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> 734 public void UploadFileAsync(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile) 735 { 736 try 737 { 738 739 if (!IsValidFileChars(RemoteFileName)) 740 { 741 throw new Exception("非法文件名!"); 742 } 743 if (!OverWriteRemoteFile && FileExist(RemoteFileName)) 744 { 745 throw new Exception("FTP服务上面已经存在同名文件!"); 746 } 747 string TempPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Templates); 748 if (!TempPath.EndsWith("\\")) 749 { 750 TempPath += "\\"; 751 } 752 string TempFile = TempPath + Path.GetRandomFileName(); 753 TempFile = Path.ChangeExtension(TempFile, Path.GetExtension(RemoteFileName)); 754 FileStream Stream = new FileStream(TempFile, FileMode.CreateNew, FileAccess.Write); 755 Stream.Write(FileBytes, 0, FileBytes.Length); //注意,因为Int32的最大限制,最大上传文件只能是大约2G多一点 756 Stream.Flush(); 757 Stream.Close(); 758 Stream.Dispose(); 759 _isDeleteTempFile = true; 760 _UploadTempFile = TempFile; 761 FileBytes = null; 762 UploadFileAsync(TempFile, RemoteFileName, OverWriteRemoteFile); 763 764 765 766 } 767 catch (Exception ep) 768 { 769 ErrorMsg = ep.ToString(); 770 throw ep; 771 } 772 } 773 774 /// <summary> 775 /// 异步上传文件完成之后触发的事件 776 /// </summary> 777 /// <param name="sender">下载对象</param> 778 /// <param name="e">数据信息对象</param> 779 void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e) 780 { 781 if (_isDeleteTempFile) 782 { 783 if (File.Exists(_UploadTempFile)) 784 { 785 File.SetAttributes(_UploadTempFile, FileAttributes.Normal); 786 File.Delete(_UploadTempFile); 787 } 788 _isDeleteTempFile = false; 789 } 790 if (UploadFileCompleted != null) 791 { 792 UploadFileCompleted(sender, e); 793 } 794 } 795 796 /// <summary> 797 /// 异步上传进度发生改变触发的事件 798 /// </summary> 799 /// <param name="sender">下载对象</param> 800 /// <param name="e">进度信息对象</param> 801 void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e) 802 { 803 if (UploadProgressChanged != null) 804 { 805 UploadProgressChanged(sender, e); 806 } 807 } 808 #endregion 809 #region 列出目录文件信息 810 /// <summary> 811 /// 列出FTP服务器上面当前目录的所有文件和目录 812 /// </summary> 813 public FileStruct[] ListFilesAndDirectories() 814 { 815 Response = Open(this.Uri, WebRequestMethods.Ftp.ListDirectoryDetails); 816 StreamReader stream = new StreamReader(Response.GetResponseStream(), Encoding.Default); 817 string Datastring = stream.ReadToEnd(); 818 FileStruct[] list = GetList(Datastring); 819 return list; 820 } 821 /// <summary> 822 /// 列出FTP服务器上面当前目录的所有文件 823 /// </summary> 824 public FileStruct[] ListFiles() 825 { 826 FileStruct[] listAll = ListFilesAndDirectories(); 827 List<FileStruct> listFile = new List<FileStruct>(); 828 foreach (FileStruct file in listAll) 829 { 830 if (!file.IsDirectory) 831 { 832 listFile.Add(file); 833 } 834 } 835 return listFile.ToArray(); 836 } 837 838 /// <summary> 839 /// 列出FTP服务器上面当前目录的所有的目录 840 /// </summary> 841 public FileStruct[] ListDirectories() 842 { 843 FileStruct[] listAll = ListFilesAndDirectories(); 844 List<FileStruct> listDirectory = new List<FileStruct>(); 845 foreach (FileStruct file in listAll) 846 { 847 if (file.IsDirectory) 848 { 849 listDirectory.Add(file); 850 } 851 } 852 return listDirectory.ToArray(); 853 } 854 /// <summary> 855 /// 获得文件和目录列表 856 /// </summary> 857 /// <param name="datastring">FTP返回的列表字符信息</param> 858 private FileStruct[] GetList(string datastring) 859 { 860 List<FileStruct> myListArray = new List<FileStruct>(); 861 string[] dataRecords = datastring.Split('\n'); 862 FileListStyle _directoryListStyle = GuessFileListStyle(dataRecords); 863 foreach (string s in dataRecords) 864 { 865 if (_directoryListStyle != FileListStyle.Unknown && s != "") 866 { 867 FileStruct f = new FileStruct(); 868 f.Name = ".."; 869 switch (_directoryListStyle) 870 { 871 case FileListStyle.UnixStyle: 872 f = ParseFileStructFromUnixStyleRecord(s); 873 break; 874 case FileListStyle.WindowsStyle: 875 f = ParseFileStructFromWindowsStyleRecord(s); 876 break; 877 } 878 if (!(f.Name == "." || f.Name == "..")) 879 { 880 myListArray.Add(f); 881 } 882 } 883 } 884 return myListArray.ToArray(); 885 } 886 887 /// <summary> 888 /// 从Windows格式中返回文件信息 889 /// </summary> 890 /// <param name="Record">文件信息</param> 891 private FileStruct ParseFileStructFromWindowsStyleRecord(string Record) 892 { 893 FileStruct f = new FileStruct(); 894 string processstr = Record.Trim(); 895 string dateStr = processstr.Substring(0, 8); 896 processstr = (processstr.Substring(8, processstr.Length - 8)).Trim(); 897 string timeStr = processstr.Substring(0, 7); 898 processstr = (processstr.Substring(7, processstr.Length - 7)).Trim(); 899 DateTimeFormatInfo myDTFI = new CultureInfo("en-US", false).DateTimeFormat; 900 myDTFI.ShortTimePattern = "t"; 901 f.CreateTime = DateTime.Parse(dateStr + " " + timeStr, myDTFI); 902 if (processstr.Substring(0, 5) == "<DIR>") 903 { 904 f.IsDirectory = true; 905 processstr = (processstr.Substring(5, processstr.Length - 5)).Trim(); 906 } 907 else 908 { 909 string[] strs = processstr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // true); 910 processstr = strs[1]; 911 f.IsDirectory = false; 912 } 913 f.Name = processstr; 914 return f; 915 } 916 917 918 /// <summary> 919 /// 判断文件列表的方式Window方式还是Unix方式 920 /// </summary> 921 /// <param name="recordList">文件信息列表</param> 922 private FileListStyle GuessFileListStyle(string[] recordList) 923 { 924 foreach (string s in recordList) 925 { 926 if (s.Length > 10 927 && Regex.IsMatch(s.Substring(0, 10), "(-|d)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)")) 928 { 929 return FileListStyle.UnixStyle; 930 } 931 else if (s.Length > 8 932 && Regex.IsMatch(s.Substring(0, 8), "[0-9][0-9]-[0-9][0-9]-[0-9][0-9]")) 933 { 934 return FileListStyle.WindowsStyle; 935 } 936 } 937 return FileListStyle.Unknown; 938 } 939 940 /// <summary> 941 /// 从Unix格式中返回文件信息 942 /// </summary> 943 /// <param name="Record">文件信息</param> 944 private FileStruct ParseFileStructFromUnixStyleRecord(string Record) 945 { 946 FileStruct f = new FileStruct(); 947 string processstr = Record.Trim(); 948 f.Flags = processstr.Substring(0, 10); 949 f.IsDirectory = (f.Flags[0] == 'd'); 950 processstr = (processstr.Substring(11)).Trim(); 951 _cutSubstringFromStringWithTrim(ref processstr, ' ', 0); //跳过一部分 952 f.Owner = _cutSubstringFromStringWithTrim(ref processstr, ' ', 0); 953 f.Group = _cutSubstringFromStringWithTrim(ref processstr, ' ', 0); 954 _cutSubstringFromStringWithTrim(ref processstr, ' ', 0); //跳过一部分 955 string yearOrTime = processstr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[2]; 956 if (yearOrTime.IndexOf(":") >= 0) //time 957 { 958 processstr = processstr.Replace(yearOrTime, DateTime.Now.Year.ToString()); 959 } 960 f.CreateTime = DateTime.Parse(_cutSubstringFromStringWithTrim(ref processstr, ' ', 8)); 961 f.Name = processstr; //最后就是名称 962 return f; 963 } 964 965 /// <summary> 966 /// 按照一定的规则进行字符串截取 967 /// </summary> 968 /// <param name="s">截取的字符串</param> 969 /// <param name="c">查找的字符</param> 970 /// <param name="startIndex">查找的位置</param> 971 private string _cutSubstringFromStringWithTrim(ref string s, char c, int startIndex) 972 { 973 int pos1 = s.IndexOf(c, startIndex); 974 string retString = s.Substring(0, pos1); 975 s = (s.Substring(pos1)).Trim(); 976 return retString; 977 } 978 #endregion 979 #region 目录或文件存在的判断 980 /// <summary> 981 /// 判断当前目录下指定的子目录是否存在 982 /// </summary> 983 /// <param name="RemoteDirectoryName">指定的目录名</param> 984 public bool DirectoryExist(string RemoteDirectoryName) 985 { 986 try 987 { 988 if (!IsValidPathChars(RemoteDirectoryName)) 989 { 990 throw new Exception("目录名非法!"); 991 } 992 FileStruct[] listDir = ListDirectories(); 993 foreach (FileStruct dir in listDir) 994 { 995 if (dir.Name == RemoteDirectoryName) 996 { 997 return true; 998 } 999 } 1000 return false; 1001 } 1002 catch (Exception ep) 1003 { 1004 ErrorMsg = ep.ToString(); 1005 throw ep; 1006 } 1007 } 1008 /// <summary> 1009 /// 判断一个远程文件是否存在服务器当前目录下面 1010 /// </summary> 1011 /// <param name="RemoteFileName">远程文件名</param> 1012 public bool FileExist(string RemoteFileName) 1013 { 1014 try 1015 { 1016 if (!IsValidFileChars(RemoteFileName)) 1017 { 1018 throw new Exception("文件名非法!"); 1019 } 1020 FileStruct[] listFile = ListFiles(); 1021 foreach (FileStruct file in listFile) 1022 { 1023 if (file.Name == RemoteFileName) 1024 { 1025 return true; 1026 } 1027 } 1028 return false; 1029 } 1030 catch (Exception ep) 1031 { 1032 ErrorMsg = ep.ToString(); 1033 throw ep; 1034 } 1035 } 1036 #endregion 1037 #region 删除文件 1038 /// <summary> 1039 /// 从FTP服务器上面删除一个文件 1040 /// </summary> 1041 /// <param name="RemoteFileName">远程文件名</param> 1042 public void DeleteFile(string RemoteFileName) 1043 { 1044 try 1045 { 1046 if (!IsValidFileChars(RemoteFileName)) 1047 { 1048 throw new Exception("文件名非法!"); 1049 } 1050 Response = Open(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.DeleteFile); 1051 } 1052 catch (Exception ep) 1053 { 1054 ErrorMsg = ep.ToString(); 1055 throw ep; 1056 } 1057 } 1058 #endregion 1059 #region 重命名文件 1060 /// <summary> 1061 /// 更改一个文件的名称或一个目录的名称 1062 /// </summary> 1063 /// <param name="RemoteFileName">原始文件或目录名称</param> 1064 /// <param name="NewFileName">新的文件或目录的名称</param> 1065 public bool ReName(string RemoteFileName, string NewFileName) 1066 { 1067 try 1068 { 1069 if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(NewFileName)) 1070 { 1071 throw new Exception("文件名非法!"); 1072 } 1073 if (RemoteFileName == NewFileName) 1074 { 1075 return true; 1076 } 1077 if (FileExist(RemoteFileName)) 1078 { 1079 Request = OpenRequest(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.Rename); 1080 Request.RenameTo = NewFileName; 1081 Response = (FtpWebResponse)Request.GetResponse(); 1082 1083 } 1084 else 1085 { 1086 throw new Exception("文件在服务器上不存在!"); 1087 } 1088 return true; 1089 } 1090 catch (Exception ep) 1091 { 1092 ErrorMsg = ep.ToString(); 1093 throw ep; 1094 } 1095 } 1096 #endregion 1097 #region 拷贝、移动文件 1098 /// <summary> 1099 /// 把当前目录下面的一个文件拷贝到服务器上面另外的目录中,注意,拷贝文件之后,当前工作目录还是文件原来所在的目录 1100 /// </summary> 1101 /// <param name="RemoteFile">当前目录下的文件名</param> 1102 /// <param name="DirectoryName">新目录名称。 1103 /// 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; 1104 /// 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如: ./NewDirectory/SubDirectory1/SubDirectory2 1105 /// </param> 1106 /// <returns></returns> 1107 public bool CopyFileToAnotherDirectory(string RemoteFile, string DirectoryName) 1108 { 1109 string CurrentWorkDir = this.DirectoryPath; 1110 try 1111 { 1112 byte[] bt = DownloadFile(RemoteFile); 1113 GotoDirectory(DirectoryName); 1114 bool Success = UploadFile(bt, RemoteFile, false); 1115 this.DirectoryPath = CurrentWorkDir; 1116 return Success; 1117 } 1118 catch (Exception ep) 1119 { 1120 this.DirectoryPath = CurrentWorkDir; 1121 ErrorMsg = ep.ToString(); 1122 throw ep; 1123 } 1124 } 1125 /// <summary> 1126 /// 把当前目录下面的一个文件移动到服务器上面另外的目录中,注意,移动文件之后,当前工作目录还是文件原来所在的目录 1127 /// </summary> 1128 /// <param name="RemoteFile">当前目录下的文件名</param> 1129 /// <param name="DirectoryName">新目录名称。 1130 /// 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; 1131 /// 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如: ./NewDirectory/SubDirectory1/SubDirectory2 1132 /// </param> 1133 /// <returns></returns> 1134 public bool MoveFileToAnotherDirectory(string RemoteFile, string DirectoryName) 1135 { 1136 string CurrentWorkDir = this.DirectoryPath; 1137 try 1138 { 1139 if (DirectoryName == "") 1140 return false; 1141 if (!DirectoryName.StartsWith("/")) 1142 DirectoryName = "/" + DirectoryName; 1143 if (!DirectoryName.EndsWith("/")) 1144 DirectoryName += "/"; 1145 bool Success = ReName(RemoteFile, DirectoryName + RemoteFile); 1146 this.DirectoryPath = CurrentWorkDir; 1147 return Success; 1148 } 1149 catch (Exception ep) 1150 { 1151 this.DirectoryPath = CurrentWorkDir; 1152 ErrorMsg = ep.ToString(); 1153 throw ep; 1154 } 1155 } 1156 #endregion 1157 #region 建立、删除子目录 1158 /// <summary> 1159 /// 在FTP服务器上当前工作目录建立一个子目录 1160 /// </summary> 1161 /// <param name="DirectoryName">子目录名称</param> 1162 public bool MakeDirectory(string DirectoryName) 1163 { 1164 try 1165 { 1166 if (!IsValidPathChars(DirectoryName)) 1167 { 1168 throw new Exception("目录名非法!"); 1169 } 1170 if (DirectoryExist(DirectoryName)) 1171 { 1172 throw new Exception("服务器上面已经存在同名的文件名或目录名!"); 1173 } 1174 Response = Open(new Uri(this.Uri.ToString() + DirectoryName), WebRequestMethods.Ftp.MakeDirectory); 1175 return true; 1176 } 1177 catch (Exception ep) 1178 { 1179 ErrorMsg = ep.ToString(); 1180 throw ep; 1181 } 1182 } 1183 /// <summary> 1184 /// 从当前工作目录中删除一个子目录 1185 /// </summary> 1186 /// <param name="DirectoryName">子目录名称</param> 1187 public bool RemoveDirectory(string DirectoryName) 1188 { 1189 try 1190 { 1191 if (!IsValidPathChars(DirectoryName)) 1192 { 1193 throw new Exception("目录名非法!"); 1194 } 1195 if (!DirectoryExist(DirectoryName)) 1196 { 1197 throw new Exception("服务器上面不存在指定的文件名或目录名!"); 1198 } 1199 Response = Open(new Uri(this.Uri.ToString() + DirectoryName), WebRequestMethods.Ftp.RemoveDirectory); 1200 return true; 1201 } 1202 catch (Exception ep) 1203 { 1204 ErrorMsg = ep.ToString(); 1205 throw ep; 1206 } 1207 } 1208 #endregion 1209 #region 文件、目录名称有效性判断 1210 /// <summary> 1211 /// 判断目录名中字符是否合法 1212 /// </summary> 1213 /// <param name="DirectoryName">目录名称</param> 1214 public bool IsValidPathChars(string DirectoryName) 1215 { 1216 char[] invalidPathChars = Path.GetInvalidPathChars(); 1217 char[] DirChar = DirectoryName.ToCharArray(); 1218 foreach (char C in DirChar) 1219 { 1220 if (Array.BinarySearch(invalidPathChars, C) >= 0) 1221 { 1222 return false; 1223 } 1224 } 1225 return true; 1226 } 1227 /// <summary> 1228 /// 判断文件名中字符是否合法 1229 /// </summary> 1230 /// <param name="FileName">文件名称</param> 1231 public bool IsValidFileChars(string FileName) 1232 { 1233 char[] invalidFileChars = Path.GetInvalidFileNameChars(); 1234 char[] NameChar = FileName.ToCharArray(); 1235 foreach (char C in NameChar) 1236 { 1237 if (Array.BinarySearch(invalidFileChars, C) >= 0) 1238 { 1239 return false; 1240 } 1241 } 1242 return true; 1243 } 1244 #endregion 1245 #region 目录切换操作 1246 /// <summary> 1247 /// 进入一个目录 1248 /// </summary> 1249 /// <param name="DirectoryName"> 1250 /// 新目录的名字。 1251 /// 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; 1252 /// 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如: ./NewDirectory/SubDirectory1/SubDirectory2 1253 /// </param> 1254 public bool GotoDirectory(string DirectoryName) 1255 { 1256 string CurrentWorkPath = this.DirectoryPath; 1257 try 1258 { 1259 DirectoryName = DirectoryName.Replace("\\", "/"); 1260 string[] DirectoryNames = DirectoryName.Split(new char[] { '/' }); 1261 if (DirectoryNames[0] == ".") 1262 { 1263 this.DirectoryPath = "/"; 1264 if (DirectoryNames.Length == 1) 1265 { 1266 return true; 1267 } 1268 Array.Clear(DirectoryNames, 0, 1); 1269 } 1270 bool Success = false; 1271 foreach (string dir in DirectoryNames) 1272 { 1273 if (dir != null) 1274 { 1275 Success = EnterOneSubDirectory(dir); 1276 if (!Success) 1277 { 1278 this.DirectoryPath = CurrentWorkPath; 1279 return false; 1280 } 1281 } 1282 } 1283 return Success; 1284 1285 } 1286 catch (Exception ep) 1287 { 1288 this.DirectoryPath = CurrentWorkPath; 1289 ErrorMsg = ep.ToString(); 1290 throw ep; 1291 } 1292 } 1293 /// <summary> 1294 /// 从当前工作目录进入一个子目录 1295 /// </summary> 1296 /// <param name="DirectoryName">子目录名称</param> 1297 public bool EnterOneSubDirectory(string DirectoryName) 1298 { 1299 try 1300 { 1301 if (DirectoryName.IndexOf("/") >= 0 || !IsValidPathChars(DirectoryName)) 1302 { 1303 throw new Exception("目录名非法!"); 1304 } 1305 if (DirectoryName.Length > 0 && DirectoryExist(DirectoryName)) 1306 { 1307 if (!DirectoryName.EndsWith("/")) 1308 { 1309 DirectoryName += "/"; 1310 } 1311 _DirectoryPath += DirectoryName; 1312 return true; 1313 } 1314 else 1315 { 1316 return false; 1317 } 1318 } 1319 catch (Exception ep) 1320 { 1321 ErrorMsg = ep.ToString(); 1322 throw ep; 1323 } 1324 } 1325 /// <summary> 1326 /// 从当前工作目录往上一级目录 1327 /// </summary> 1328 public bool ComeoutDirectory() 1329 { 1330 if (_DirectoryPath == "/") 1331 { 1332 ErrorMsg = "当前目录已经是根目录!"; 1333 throw new Exception("当前目录已经是根目录!"); 1334 } 1335 char[] sp = new char[1] { '/' }; 1336 1337 string[] strDir = _DirectoryPath.Split(sp, StringSplitOptions.RemoveEmptyEntries); 1338 if (strDir.Length == 1) 1339 { 1340 _DirectoryPath = "/"; 1341 } 1342 else 1343 { 1344 _DirectoryPath = String.Join("/", strDir, 0, strDir.Length - 1); 1345 } 1346 return true; 1347 1348 } 1349 #endregion 1350 #region 重载WebClient,支持FTP进度 1351 internal class MyWebClient : WebClient 1352 { 1353 protected override WebRequest GetWebRequest(Uri address) 1354 { 1355 FtpWebRequest req = (FtpWebRequest)base.GetWebRequest(address); 1356 req.UsePassive = false; 1357 return req; 1358 } 1359 } 1360 #endregion 1361 1362 #region "测试连接" 1363 /// <summary> 1364 /// 测试ftp连接 1365 /// </summary> 1366 /// <returns></returns> 1367 public string TestConnection(bool EnableSsl=false) 1368 { 1369 FtpWebResponse ftpRes = null; 1370 try 1371 { 1372 Request = (FtpWebRequest)WebRequest.Create(this.Uri); 1373 Request.Method = WebRequestMethods.Ftp.ListDirectory; 1374 Request.UseBinary = true; 1375 Request.EnableSsl = EnableSsl; 1376 Request.Credentials = new NetworkCredential(this.UserName, this.Password); 1377 if (this.Proxy != null) 1378 { 1379 Request.Proxy = this.Proxy; 1380 } 1381 ftpRes= (FtpWebResponse)Request.GetResponse(); 1382 if (ftpRes != null) 1383 { 1384 return "FTP连接测试成功"; 1385 } 1386 else 1387 { 1388 return "FTP连接测试失败"; 1389 } 1390 } 1391 catch (Exception ep) 1392 { 1393 ErrorMsg = ep.ToString(); 1394 return "FTP连接测试失败,错误信息:" + ErrorMsg; 1395 } 1396 } 1397 #endregion 1398 } 1399 }