FTP客户端类(C#)

最近在搞FTP,挺头大的,后来索性在网上找了个FTP的类,直接调用函数即可。由于网上的版本较多,我用的这个测试了下,比较好用。现共享给大家。

 

  1 using System;
  2 using System.Net;
  3 using System.IO;
  4 using System.Text;
  5 using System.Net.Sockets;
  6 
  7 namespace WindowsFormsApplication1
  8 {
  9     public class FTPClient
 10     {
 11         #region 构造函数
 12         /// <summary>
 13         /// 缺省构造函数
 14         /// </summary>
 15         public FTPClient()
 16         {
 17             strRemoteHost = "";
 18             strRemotePath = "";
 19             strRemoteUser = "";
 20             strRemotePass = "";
 21             strRemotePort = 21;
 22             bConnected = false;
 23         }
 24 
 25         /// <summary>
 26         /// 构造函数
 27         /// </summary>
 28         /// <param name="remoteHost"></param>
 29         /// <param name="remotePath"></param>
 30         /// <param name="remoteUser"></param>
 31         /// <param name="remotePass"></param>
 32         /// <param name="remotePort"></param>
 33         public FTPClient(string remoteHost, string remotePath, string remoteUser, string remotePass, int remotePort)
 34         {
 35             strRemoteHost = remoteHost;
 36             strRemotePath = remotePath;
 37             strRemoteUser = remoteUser;
 38             strRemotePass = remotePass;
 39             strRemotePort = remotePort;
 40             Connect();
 41         }
 42         #endregion
 43 
 44         #region 登陆
 45         /// <summary>
 46         /// FTP服务器IP地址
 47         /// </summary>
 48         private string strRemoteHost;
 49         public string RemoteHost
 50         {
 51             get
 52             {
 53                 return strRemoteHost;
 54             }
 55             set
 56             {
 57                 strRemoteHost = value;
 58             }
 59         }
 60         /// <summary>
 61         /// FTP服务器端口
 62         /// </summary>
 63         private int strRemotePort;
 64         public int RemotePort
 65         {
 66             get
 67             {
 68                 return strRemotePort;
 69             }
 70             set
 71             {
 72                 strRemotePort = value;
 73             }
 74         }
 75         /// <summary>
 76         /// 当前服务器目录
 77         /// </summary>
 78         private string strRemotePath;
 79         public string RemotePath
 80         {
 81             get
 82             {
 83                 return strRemotePath;
 84             }
 85             set
 86             {
 87                 strRemotePath = value;
 88             }
 89         }
 90         /// <summary>
 91         /// 登录用户账号
 92         /// </summary>
 93         private string strRemoteUser;
 94         public string RemoteUser
 95         {
 96             set
 97             {
 98                 strRemoteUser = value;
 99             }
100         }
101         /// <summary>
102         /// 用户登录密码
103         /// </summary>
104         private string strRemotePass;
105         public string RemotePass
106         {
107             set
108             {
109                 strRemotePass = value;
110             }
111         }
112 
113         /// <summary>
114         /// 是否登录
115         /// </summary>
116         private Boolean bConnected;
117         public bool Connected
118         {
119             get
120             {
121                 return bConnected;
122             }
123         }
124         #endregion
125 
126         #region 链接
127         /// <summary>
128         /// 建立连接 
129         /// </summary>
130         public void Connect()
131         {
132             socketControl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
133             IPEndPoint ep = new IPEndPoint(IPAddress.Parse(RemoteHost), strRemotePort);
134             // 链接
135             try
136             {
137                 socketControl.Connect(ep);
138             }
139             catch (Exception)
140             {
141                 throw new IOException("Couldn't connect to remote server");
142             }
143 
144             // 获取应答码
145             ReadReply();
146             if (iReplyCode != 220)
147             {
148                 DisConnect();
149                 throw new IOException(strReply.Substring(4));
150             }
151 
152             // 登陆
153             SendCommand("USER " + strRemoteUser);
154             if (!(iReplyCode == 331 || iReplyCode == 230))
155             {
156                 CloseSocketConnect();//关闭连接
157                 throw new IOException(strReply.Substring(4));
158             }
159             if (iReplyCode != 230)
160             {
161                 SendCommand("PASS " + strRemotePass);
162                 if (!(iReplyCode == 230 || iReplyCode == 202))
163                 {
164                     CloseSocketConnect();//关闭连接
165                     throw new IOException(strReply.Substring(4));
166                 }
167             }
168             bConnected = true;
169 
170             // 切换到目录
171             ChDir(strRemotePath);
172         }
173 
174 
175         /// <summary>
176         /// 关闭连接
177         /// </summary>
178         public void DisConnect()
179         {
180             if (socketControl != null)
181             {
182                 SendCommand("QUIT");
183             }
184             CloseSocketConnect();
185         }
186 
187         #endregion
188 
189         #region 传输模式
190 
191         /// <summary>
192         /// 传输模式:二进制类型、ASCII类型
193         /// </summary>
194         public enum TransferType { Binary, ASCII };
195 
196         /// <summary>
197         /// 设置传输模式
198         /// </summary>
199         /// <param name="ttType">传输模式</param>
200         public void SetTransferType(TransferType ttType)
201         {
202             if (ttType == TransferType.Binary)
203             {
204                 SendCommand("TYPE I");//binary类型传输
205             }
206             else
207             {
208                 SendCommand("TYPE A");//ASCII类型传输
209             }
210             if (iReplyCode != 200)
211             {
212                 throw new IOException(strReply.Substring(4));
213             }
214             else
215             {
216                 trType = ttType;
217             }
218         }
219 
220 
221         /// <summary>
222         /// 获得传输模式
223         /// </summary>
224         /// <returns>传输模式</returns>
225         public TransferType GetTransferType()
226         {
227             return trType;
228         }
229 
230         #endregion
231 
232         #region 文件操作
233         /// <summary>
234         /// 获得文件列表
235         /// </summary>
236         /// <param name="strMask">文件名的匹配字符串</param>
237         /// <returns></returns>
238         public string[] Dir(string strMask)
239         {
240             // 建立链接
241             if (!bConnected)
242             {
243                 Connect();
244             }
245 
246             //建立进行数据连接的socket
247             Socket socketData = CreateDataSocket();
248 
249             //传送命令
250             SendCommand("NLST " + strMask);
251 
252             //分析应答代码
253             if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226))
254             {
255                 throw new IOException(strReply.Substring(4));
256             }
257 
258             //获得结果
259             strMsg = "";
260             while (true)
261             {
262                 int iBytes = socketData.Receive(buffer, buffer.Length, 0);
263                 strMsg += Encoding.Default.GetString(buffer, 0, iBytes);
264                 if (iBytes < buffer.Length)
265                 {
266                     break;
267                 }
268             }
269             char[] seperator = "\r\n".ToCharArray();
270             string[] strsFileList = strMsg.Split(seperator, StringSplitOptions.RemoveEmptyEntries);
271             socketData.Close();//数据socket关闭时也会有返回码
272             if (iReplyCode != 226)
273             {
274                 ReadReply();
275                 if (iReplyCode != 226)
276                 {
277                     throw new IOException(strReply.Substring(4));
278                 }
279             }
280             return strsFileList;
281         }
282 
283 
284         /// <summary>
285         /// 获取文件大小
286         /// </summary>
287         /// <param name="strFileName">文件名</param>
288         /// <returns>文件大小</returns>
289         private long GetFileSize(string strFileName)
290         {
291             if (!bConnected)
292             {
293                 Connect();
294             }
295             SendCommand("SIZE " + Path.GetFileName(strFileName));
296             long lSize = 0;
297             if (iReplyCode == 213)
298             {
299                 lSize = Int64.Parse(strReply.Substring(4));
300             }
301             else
302             {
303                 throw new IOException(strReply.Substring(4));
304             }
305             return lSize;
306         }
307 
308         /// <summary>
309         /// 获得文件详细信息列表
310         /// </summary>
311         /// <param name="strMask">文件名的匹配字符串</param>
312         /// <returns></returns>
313         public string[] List(string strMask)
314         {
315             // 建立链接
316             if (!bConnected)
317             {
318                 Connect();
319             }
320 
321             //建立进行数据连接的socket
322             Socket socketData = CreateDataSocket();
323 
324             //传送命令
325             SendCommand("LIST " + strMask);
326 
327             //分析应答代码
328             if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226))
329             {
330                 throw new IOException(strReply.Substring(4));
331             }
332 
333             //获得结果
334             strMsg = "";
335             while (true)
336             {
337                 int iBytes = socketData.Receive(buffer, buffer.Length, 0);
338                 strMsg += Encoding.Default.GetString(buffer, 0, iBytes);
339                 if (iBytes < buffer.Length)
340                 {
341                     break;
342                 }
343             }
344             char[] seperator = "\r\n".ToCharArray();
345             string[] strsFileList = strMsg.Split(seperator, StringSplitOptions.RemoveEmptyEntries);
346             socketData.Close();//数据socket关闭时也会有返回码
347             if (iReplyCode != 226)
348             {
349                 ReadReply();
350                 if (iReplyCode != 226)
351                 {
352                     throw new IOException(strReply.Substring(4));
353                 }
354             }
355             return strsFileList;
356         }
357 
358 
359         /// <summary>
360         /// 删除
361         /// </summary>
362         /// <param name="strFileName">待删除文件名</param>
363         public void Delete(string strFileName)
364         {
365             if (!bConnected)
366             {
367                 Connect();
368             }
369             SendCommand("DELE " + strFileName);
370             if (iReplyCode != 250)
371             {
372                 throw new IOException(strReply.Substring(4));
373             }
374         }
375 
376 
377         /// <summary>
378         /// 重命名(如果新文件名与已有文件重名,将覆盖已有文件)
379         /// </summary>
380         /// <param name="strOldFileName">旧文件名</param>
381         /// <param name="strNewFileName">新文件名</param>
382         public void Rename(string strOldFileName, string strNewFileName)
383         {
384             if (!bConnected)
385             {
386                 Connect();
387             }
388             SendCommand("RNFR " + strOldFileName);
389             if (iReplyCode != 350)
390             {
391                 throw new IOException(strReply.Substring(4));
392             }
393             //  如果新文件名与原有文件重名,将覆盖原有文件
394             SendCommand("RNTO " + strNewFileName);
395             if (iReplyCode != 250)
396             {
397                 throw new IOException(strReply.Substring(4));
398             }
399         }
400         #endregion
401 
402         #region 上传和下载
403         /// <summary>
404         /// 下载一批文件
405         /// </summary>
406         /// <param name="strFileNameMask">文件名的匹配字符串</param>
407         /// <param name="strFolder">本地目录(不得以\结束)</param>
408         public void Get(string strFileNameMask, string strFolder)
409         {
410             if (!bConnected)
411             {
412                 Connect();
413             }
414             string[] strFiles = Dir(strFileNameMask);
415             foreach (string strFile in strFiles)
416             {
417                 if (!strFile.Equals(""))//一般来说strFiles的最后一个元素可能是空字符串
418                 {
419                     Get(strFile, strFolder, strFile);
420                 }
421             }
422         }
423 
424 
425         /// <summary>
426         /// 下载一个文件
427         /// </summary>
428         /// <param name="strRemoteFileName">要下载的文件名</param>
429         /// <param name="strFolder">本地目录(不得以\结束)</param>
430         /// <param name="strLocalFileName">保存在本地时的文件名</param>
431         public void Get(string strRemoteFileName, string strFolder, string strLocalFileName)
432         {
433             if (!bConnected)
434             {
435                 Connect();
436             }
437             SetTransferType(TransferType.Binary);
438             if (strLocalFileName.Equals(""))
439             {
440                 strLocalFileName = strRemoteFileName;
441             }
442             if (!File.Exists(strLocalFileName))
443             {
444                 Stream st = File.Create(strLocalFileName);
445                 st.Close();
446             }
447             FileStream output = new
448                 FileStream(strFolder + "\\" + strLocalFileName, FileMode.Create);
449             Socket socketData = CreateDataSocket();
450             SendCommand("RETR " + strRemoteFileName);
451             if (!(iReplyCode == 150 || iReplyCode == 125
452                 || iReplyCode == 226 || iReplyCode == 250))
453             {
454                 throw new IOException(strReply.Substring(4));
455             }
456             while (true)
457             {
458                 int iBytes = socketData.Receive(buffer, buffer.Length, 0);
459                 output.Write(buffer, 0, iBytes);
460                 if (iBytes <= 0)
461                 {
462                     break;
463                 }
464             }
465             output.Close();
466             if (socketData.Connected)
467             {
468                 socketData.Close();
469             }
470             if (!(iReplyCode == 226 || iReplyCode == 250))
471             {
472                 ReadReply();
473                 if (!(iReplyCode == 226 || iReplyCode == 250))
474                 {
475                     throw new IOException(strReply.Substring(4));
476                 }
477             }
478         }
479 
480 
481         /// <summary>
482         /// 上传一批文件
483         /// </summary>
484         /// <param name="strFolder">本地目录(不得以\结束)</param>
485         /// <param name="strFileNameMask">文件名匹配字符(可以包含*和?)</param>
486         public void Put(string strFolder, string strFileNameMask)
487         {
488             string[] strFiles = Directory.GetFiles(strFolder, strFileNameMask);
489             foreach (string strFile in strFiles)
490             {
491                 //strFile是完整的文件名(包含路径)
492                 Put(strFile);
493             }
494         }
495 
496 
497         /// <summary>
498         /// 上传一个文件
499         /// </summary>
500         /// <param name="strFileName">本地文件名</param>
501         public void Put(string strFileName)
502         {
503             if (!bConnected)
504             {
505                 Connect();
506             }
507             Socket socketData = CreateDataSocket();
508             SendCommand("STOR " + Path.GetFileName(strFileName));
509             if (!(iReplyCode == 125 || iReplyCode == 150))
510             {
511                 throw new IOException(strReply.Substring(4));
512             }
513             FileStream input = new
514                 FileStream(strFileName, FileMode.Open);
515             int iBytes = 0;
516             while ((iBytes = input.Read(buffer, 0, buffer.Length)) > 0)
517             {
518                 socketData.Send(buffer, iBytes, 0);
519             }
520             input.Close();
521             if (socketData.Connected)
522             {
523                 socketData.Close();
524             }
525             if (!(iReplyCode == 226 || iReplyCode == 250))
526             {
527                 ReadReply();
528                 if (!(iReplyCode == 226 || iReplyCode == 250))
529                 {
530                     throw new IOException(strReply.Substring(4));
531                 }
532             }
533         }
534 
535         #endregion
536 
537         #region 目录操作
538         /// <summary>
539         /// 创建目录
540         /// </summary>
541         /// <param name="strDirName">目录名</param>
542         public void MkDir(string strDirName)
543         {
544             if (!bConnected)
545             {
546                 Connect();
547             }
548             SendCommand("MKD " + strDirName);
549             if (iReplyCode != 257)
550             {
551                 throw new IOException(strReply.Substring(4));
552             }
553         }
554 
555 
556         /// <summary>
557         /// 删除目录
558         /// </summary>
559         /// <param name="strDirName">目录名</param>
560         public void RmDir(string strDirName)
561         {
562             if (!bConnected)
563             {
564                 Connect();
565             }
566             SendCommand("RMD " + strDirName);
567             if (iReplyCode != 250)
568             {
569                 throw new IOException(strReply.Substring(4));
570             }
571         }
572 
573 
574         /// <summary>
575         /// 改变目录
576         /// </summary>
577         /// <param name="strDirName">新的工作目录名</param>
578         public void ChDir(string strDirName)
579         {
580             if (strDirName.Equals("."|| strDirName.Equals(""))
581             {
582                 return;
583             }
584             if (!bConnected)
585             {
586                 Connect();
587             }
588             SendCommand("CWD " + strDirName);
589             if (iReplyCode != 250)
590             {
591                 throw new IOException(strReply.Substring(4));
592             }
593             strRemotePath = strDirName;
594         }
595 
596         #endregion
597 
598         #region 内部变量
599         /// <summary>
600         /// 服务器返回的应答信息(包含应答码)
601         /// </summary>
602         private string strMsg;
603         /// <summary>
604         /// 服务器返回的应答信息(包含应答码)
605         /// </summary>
606         private string strReply;
607         /// <summary>
608         /// 服务器返回的应答码
609         /// </summary>
610         private int iReplyCode;
611         /// <summary>
612         /// 进行控制连接的socket
613         /// </summary>
614         private Socket socketControl;
615         /// <summary>
616         /// 传输模式
617         /// </summary>
618         private TransferType trType;
619         /// <summary>
620         /// 接收和发送数据的缓冲区
621         /// </summary>
622         private static int BLOCK_SIZE = 512;
623         Byte[] buffer = new Byte[BLOCK_SIZE];
624         /// <summary>
625         /// 编码方式
626         /// </summary>
627         Encoding ASCII = Encoding.ASCII;
628         #endregion
629 
630         #region 内部函数
631         /// <summary>
632         /// 将一行应答字符串记录在strReply和strMsg
633         /// 应答码记录在iReplyCode
634         /// </summary>
635         private void ReadReply()
636         {
637             strMsg = "";
638             strReply = ReadLine();
639             iReplyCode = Int32.Parse(strReply.Substring(03));
640         }
641 
642         /// <summary>
643         /// 建立进行数据连接的socket
644         /// </summary>
645         /// <returns>数据连接socket</returns>
646         private Socket CreateDataSocket()
647         {
648             SendCommand("PASV");
649             if (iReplyCode != 227)
650             {
651                 throw new IOException(strReply.Substring(4));
652             }
653             int index1 = strReply.IndexOf('(');
654             int index2 = strReply.IndexOf(')');
655             string ipData =
656                 strReply.Substring(index1 + 1, index2 - index1 - 1);
657             int[] parts = new int[6];
658             int len = ipData.Length;
659             int partCount = 0;
660             string buf = "";
661             for (int i = 0; i < len && partCount <= 6; i++)
662             {
663                 char ch = Char.Parse(ipData.Substring(i, 1));
664                 if (Char.IsDigit(ch))
665                     buf += ch;
666                 else if (ch != ',')
667                 {
668                     throw new IOException("Malformed PASV strReply: " +
669                         strReply);
670                 }
671                 if (ch == ',' || i + 1 == len)
672                 {
673                     try
674                     {
675                         parts[partCount++= Int32.Parse(buf);
676                         buf = "";
677                     }
678                     catch (Exception)
679                     {
680                         throw new IOException("Malformed PASV strReply: " +
681                             strReply);
682                     }
683                 }
684             }
685             string ipAddress = parts[0+ "." + parts[1+ "." +
686                 parts[2+ "." + parts[3];
687             int port = (parts[4<< 8+ parts[5];
688             Socket s = new
689                 Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
690             IPEndPoint ep = new
691                 IPEndPoint(IPAddress.Parse(ipAddress), port);
692             try
693             {
694                 s.Connect(ep);
695             }
696             catch (Exception)
697             {
698                 throw new IOException("Can't connect to remote server");
699             }
700             return s;
701         }
702 
703 
704         /// <summary>
705         /// 关闭socket连接(用于登录以前)
706         /// </summary>
707         private void CloseSocketConnect()
708         {
709             if (socketControl != null)
710             {
711                 socketControl.Close();
712                 socketControl = null;
713             }
714             bConnected = false;
715         }
716 
717         /// <summary>
718         /// 读取Socket返回的所有字符串
719         /// </summary>
720         /// <returns>包含应答码的字符串行</returns>
721         private string ReadLine()
722         {
723             while (true)
724             {
725                 int iBytes = socketControl.Receive(buffer, buffer.Length, 0);
726                 strMsg += ASCII.GetString(buffer, 0, iBytes);
727                 if (iBytes < buffer.Length)
728                 {
729                     break;
730                 }
731             }
732             char[] seperator = { '\n' };
733             string[] mess = strMsg.Split(seperator);
734             if (strMsg.Length > 2)
735             {
736                 strMsg = mess[mess.Length - 2];
737                 //seperator[0]是10,换行符是由13和0组成的,分隔后10后面虽没有字符串,
738                 //但也会分配为空字符串给后面(也是最后一个)字符串数组,
739                 //所以最后一个mess是没用的空字符串
740                 //但为什么不直接取mess[0],因为只有最后一行字符串应答码与信息之间有空格
741             }
742             else
743             {
744                 strMsg = mess[0];
745             }
746             if (!strMsg.Substring(31).Equals(" "))//返回字符串正确的是以应答码(如220开头,后面接一空格,再接问候字符串)
747             {
748                 return ReadLine();
749             }
750             return strMsg;
751         }
752 
753 
754         /// <summary>
755         /// 发送命令并获取应答码和最后一行应答字符串
756         /// </summary>
757         /// <param name="strCommand">命令</param>
758         private void SendCommand(String strCommand)
759         {
760             Byte[] cmdBytes =
761                 Encoding.Default.GetBytes((strCommand + "\r\n").ToCharArray());
762             socketControl.Send(cmdBytes, cmdBytes.Length, 0);
763             ReadReply();
764         }
765 
766         #endregion
767     }
768 }
769 

 

posted on 2009-11-18 15:19  李福伟  阅读(6172)  评论(0编辑  收藏  举报

导航