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