
using System;

using System.Net;

using System.IO;

using System.Text;

using System.Net.Sockets;


namespace ftpGet

{

/// <summary>

/// FTP Client

/// </summary>

public class FTPClient

{

构造函数


登陆字段、属性


链接


传输模式


文件操作


#region 上传和下载

/// <summary>

/// 下载一批文件

/// </summary>

/// <param name="strFileNameMask">文件名的匹配字符串</param>

/// <param name="strFolder">本地目录(不得以\结束)</param>

public void Get(string strFileNameMask, string strFolder)

{

if (!bConnected)

{

Connect();

}

string[] strFiles = Dir(strFileNameMask);

foreach (string strFile in strFiles)

{

if (!strFile.Equals(""))//一般来说strFiles的最后一个元素可能是空字符串

{

if (strFile.LastIndexOf(".") > -1)

{

Get(strFile.Replace("\r", ""), strFolder, strFile.Replace("\r", ""));

}

}

}

}



/// <summary>

/// 下载目录

/// </summary>

/// <param name="strRemoteFileName">要下载的文件名</param>

/// <param name="strFolder">本地目录(不得以\结束)</param>

/// <param name="strLocalFileName">保存在本地时的文件名</param>

public void Get(string strRemoteFileName, string strFolder, string strLocalFileName)

{

if (strLocalFileName.StartsWith("-r"))

{

string[] infos = strLocalFileName.Split(' ');

strRemoteFileName=strLocalFileName = infos[infos.Length - 1];


if (!bConnected)

{

Connect();

}

SetTransferType(TransferType.Binary);

if (strLocalFileName.Equals(""))

{

strLocalFileName = strRemoteFileName;

}

if (!File.Exists(strLocalFileName))

{

Stream st = File.Create(strLocalFileName);

st.Close();

}


FileStream output = new

FileStream(strFolder + "\\" + strLocalFileName, FileMode.Create);

Socket socketData = CreateDataSocket();

SendCommand("RETR " + strRemoteFileName);

if (!(iReplyCode == 150 || iReplyCode == 125

|| iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}

while (true)

{

int iBytes = socketData.Receive(buffer, buffer.Length, 0);

output.Write(buffer, 0, iBytes);

if (iBytes <= 0)

{

break;

}

}

output.Close();

if (socketData.Connected)

{

socketData.Close();

}

if (!(iReplyCode == 226 || iReplyCode == 250))

{

ReadReply();

if (!(iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}

}

}

}


/// <summary>

/// 下载一个文件

/// </summary>

/// <param name="strRemoteFileName">要下载的文件名</param>

/// <param name="strFolder">本地目录(不得以\结束)</param>

/// <param name="strLocalFileName">保存在本地时的文件名</param>

public void GetFile(string strRemoteFileName, string strFolder, string strLocalFileName)

{

if (!bConnected)

{

Connect();

}

SetTransferType(TransferType.Binary);

if (strLocalFileName.Equals(""))

{

strLocalFileName = strRemoteFileName;

}

if (!File.Exists(strLocalFileName))

{

Stream st = File.Create(strLocalFileName);

st.Close();

}


FileStream output = new

FileStream(strFolder + "\\" + strLocalFileName, FileMode.Create);

Socket socketData = CreateDataSocket();

SendCommand("RETR " + strRemoteFileName);

if (!(iReplyCode == 150 || iReplyCode == 125

|| iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}

while (true)

{

int iBytes = socketData.Receive(buffer, buffer.Length, 0);

output.Write(buffer, 0, iBytes);

if (iBytes <= 0)

{

break;

}

}

output.Close();

if (socketData.Connected)

{

socketData.Close();

}

if (!(iReplyCode == 226 || iReplyCode == 250))

{

ReadReply();

if (!(iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}

}

}


/// <summary>

/// 下载一个文件

/// </summary>

/// <param name="strRemoteFileName">要下载的文件名</param>

/// <param name="strFolder">本地目录(不得以\结束)</param>

/// <param name="strLocalFileName">保存在本地时的文件名</param>

public void GetBrokenFile(string strRemoteFileName, string strFolder, string strLocalFileName,long size)

{

if (!bConnected)

{

Connect();

}

SetTransferType(TransferType.Binary);



FileStream output = new

FileStream(strFolder + "\\" + strLocalFileName, FileMode.Append);

Socket socketData = CreateDataSocket();

SendCommand("REST " + size.ToString());

SendCommand("RETR " + strRemoteFileName);

if (!(iReplyCode == 150 || iReplyCode == 125

|| iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}


//int byteYu = (int)size % 512;

//int byteChu = (int)size / 512;

//byte[] tempBuffer = new byte[byteYu];

//for (int i = 0; i < byteChu; i++)

//{

// socketData.Receive(buffer, buffer.Length, 0);

//}

//socketData.Receive(tempBuffer, tempBuffer.Length, 0);


//socketData.Receive(buffer, byteYu, 0);

while (true)

{

int iBytes = socketData.Receive(buffer, buffer.Length, 0);

//totalBytes += iBytes;

output.Write(buffer, 0, iBytes);

if (iBytes <= 0)

{

break;

}

}

output.Close();

if (socketData.Connected)

{

socketData.Close();

}

if (!(iReplyCode == 226 || iReplyCode == 250))

{

ReadReply();

if (!(iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}

}

}




/// <summary>

/// 上传一批文件

/// </summary>

/// <param name="strFolder">本地目录(不得以\结束)</param>

/// <param name="strFileNameMask">文件名匹配字符(可以包含*和?)</param>

public void Put(string strFolder, string strFileNameMask)

{

string[] strFiles = Directory.GetFiles(strFolder, strFileNameMask);

foreach (string strFile in strFiles)

{

//strFile是完整的文件名(包含路径)

Put(strFile);

}

}



/// <summary>

/// 上传一个文件

/// </summary>

/// <param name="strFileName">本地文件名</param>

public void Put(string strFileName)

{

if (!bConnected)

{

Connect();

}

Socket socketData = CreateDataSocket();

SendCommand("STOR " + Path.GetFileName(strFileName));

if (!(iReplyCode == 125 || iReplyCode == 150))

{

throw new IOException(strReply.Substring(4));

}

FileStream input = new

FileStream(strFileName, FileMode.Open);

int iBytes = 0;

while ((iBytes = input.Read(buffer, 0, buffer.Length)) > 0)

{

socketData.Send(buffer, iBytes, 0);

}

input.Close();

if (socketData.Connected)

{

socketData.Close();

}

if (!(iReplyCode == 226 || iReplyCode == 250))

{

ReadReply();

if (!(iReplyCode == 226 || iReplyCode == 250))

{

throw new IOException(strReply.Substring(4));

}

}

}


#endregion


#region 目录操作

/// <summary>

/// 创建目录

/// </summary>

/// <param name="strDirName">目录名</param>

public void MkDir(string strDirName)

{

if (!bConnected)

{

Connect();

}

SendCommand("MKD " + strDirName);

if (iReplyCode != 257)

{

throw new IOException(strReply.Substring(4));

}

}



/// <summary>

/// 删除目录

/// </summary>

/// <param name="strDirName">目录名</param>

public void RmDir(string strDirName)

{

if (!bConnected)

{

Connect();

}

SendCommand("RMD " + strDirName);

if (iReplyCode != 250)

{

throw new IOException(strReply.Substring(4));

}

}



/// <summary>

/// 改变目录

/// </summary>

/// <param name="strDirName">新的工作目录名</param>

public void ChDir(string strDirName)

{

if (strDirName.Equals(".") || strDirName.Equals(""))

{

return;

}

if (!bConnected)

{

Connect();

}

SendCommand("CWD " + strDirName);

if (iReplyCode != 250)

{

throw new IOException(strReply.Substring(4));

}

this.strRemotePath = strDirName;

}


#endregion


#region 内部变量

/// <summary>

/// 服务器返回的应答信息(包含应答码)

/// </summary>

private string strMsg;

/// <summary>

/// 服务器返回的应答信息(包含应答码)

/// </summary>

private string strReply;

/// <summary>

/// 服务器返回的应答码

/// </summary>

private int iReplyCode;

/// <summary>

/// 进行控制连接的socket

/// </summary>

private Socket socketControl;

/// <summary>

/// 传输模式

/// </summary>

private TransferType trType;

/// <summary>

/// 接收和发送数据的缓冲区

/// </summary>

private static int BLOCK_SIZE = 512;

Byte[] buffer = new Byte[BLOCK_SIZE];

/// <summary>

/// 编码方式(为防止出现中文乱码采用 GB2312编码方式)

/// </summary>

Encoding GB2312 = Encoding.GetEncoding("gb2312");

#endregion


#region 内部函数

/// <summary>

/// 将一行应答字符串记录在strReply和strMsg

/// 应答码记录在iReplyCode

/// </summary>

private void ReadReply()

{

strMsg = "";

strReply = ReadLine();

iReplyCode = Int32.Parse(strReply.Substring(0, 3));

}


/// <summary>

/// 建立进行数据连接的socket

/// </summary>

/// <returns>数据连接socket</returns>

private Socket CreateDataSocket()

{

SendCommand("PASV");

if (iReplyCode != 227)

{

throw new IOException(strReply.Substring(4));

}

int index1 = strReply.IndexOf('(');

int index2 = strReply.IndexOf(')');

string ipData =

strReply.Substring(index1 + 1, index2 - index1 - 1);

int[] parts = new int[6];

int len = ipData.Length;

int partCount = 0;

string buf = "";

for (int i = 0; i < len && partCount <= 6; i++)

{

char ch = Char.Parse(ipData.Substring(i, 1));

if (Char.IsDigit(ch))

buf += ch;

else if (ch != ',')

{

throw new IOException("Malformed PASV strReply: " +

strReply);

}

if (ch == ',' || i + 1 == len)

{

try

{

parts[partCount++] = Int32.Parse(buf);

buf = "";

}

catch (Exception)

{

throw new IOException("Malformed PASV strReply: " +

strReply);

}

}

}

string ipAddress = parts[0] + "." + parts[1] + "." +

parts[2] + "." + parts[3];

int port = (parts[4] << 8) + parts[5];

Socket s = new

Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPEndPoint ep = new

IPEndPoint(IPAddress.Parse(ipAddress), port);

try

{

s.Connect(ep);

}

catch (Exception)

{

throw new IOException("Can't connect to remote server");

}

return s;

}



/// <summary>

/// 关闭socket连接(用于登录以前)

/// </summary>

private void CloseSocketConnect()

{

if (socketControl != null)

{

socketControl.Close();

socketControl = null;

}

bConnected = false;

}


/// <summary>

/// 读取Socket返回的所有字符串

/// </summary>

/// <returns>包含应答码的字符串行</returns>

private string ReadLine()

{

while (true)

{

int iBytes = socketControl.Receive(buffer, buffer.Length, 0);

strMsg += GB2312.GetString(buffer, 0, iBytes);

if (iBytes < buffer.Length)

{

break;

}

}

char[] seperator = { '\n' };

string[] mess = strMsg.Split(seperator);

if (strMsg.Length > 2)

{

strMsg = mess[mess.Length - 2];

//seperator[0]是10,换行符是由13和0组成的,分隔后10后面虽没有字符串,

//但也会分配为空字符串给后面(也是最后一个)字符串数组,

//所以最后一个mess是没用的空字符串

//但为什么不直接取mess[0],因为只有最后一行字符串应答码与信息之间有空格

}

else

{

strMsg = mess[0];

}

if (!strMsg.Substring(3, 1).Equals(" "))//返回字符串正确的是以应答码(如220开头,后面接一空格,再接问候字符串)

{

return ReadLine();

}

return strMsg;

}



/// <summary>

/// 发送命令并获取应答码和最后一行应答字符串

/// </summary>

/// <param name="strCommand">命令</param>

private void SendCommand(String strCommand)

{

Byte[] cmdBytes =

GB2312.GetBytes((strCommand + "\r\n").ToCharArray());

socketControl.Send(cmdBytes, cmdBytes.Length, 0);

ReadReply();

}


#endregion

}

}


using System;

using System.Collections.Generic;

using System.Text;

using System.IO;


namespace ftpGet

{

class Program

{

static string remotingFolder = System.Configuration.ConfigurationSettings.AppSettings["remotingFolder"]; //远程ftp文件目录

static string localFolder = System.Configuration.ConfigurationSettings.AppSettings["localFolder"]; //要下载到的本地目录

static string ftpServer = System.Configuration.ConfigurationSettings.AppSettings["ftpServer"]; //ftp服务器

static string user = System.Configuration.ConfigurationSettings.AppSettings["user"]; //用户名

static string pwd = System.Configuration.ConfigurationSettings.AppSettings["pwd"]; //密码

static string port = System.Configuration.ConfigurationSettings.AppSettings["port"]; //端口

static void Main(string[] args)

{

FTPClient client = new FTPClient(ftpServer, "/", user, pwd, int.Parse(port));

client.Connect();

GetFolder("*", remotingFolder, client, CreateFolder());

client.DisConnect();

ClearFolder();

Console.WriteLine("下载完毕");

System.Threading.Thread.Sleep(3000);

}


/// <summary>

/// 在本地目录下创建一个以日期为名称的目录,我做这个ftp的主要目的是为了每天都备份

/// </summary>

/// <returns>创建的目录名</returns>

private static string CreateFolder()

{

string folder=localFolder + "\\"+DateTime.Now.ToShortDateString();

if (!Directory.Exists(folder))

Directory.CreateDirectory(folder);

return folder;

}


/// <summary>

/// 在下载结束后清空程序目录的多余文件

/// </summary>

private static void ClearFolder()

{

string folder = Environment.CurrentDirectory;

string[] dictorys = Directory.GetFiles(folder);

foreach (string dictory in dictorys)

{

FileInfo info = new FileInfo(dictory);

if (info.Length == 0)

File.Delete(dictory);

}

}


/// <summary>

/// 递归获取ftp文件夹的内容

/// </summary>

/// <param name="fileMark">文件标记</param>

/// <param name="path">远程路径</param>

/// <param name="client"></param>

/// <param name="folder"></param>

private static void GetFolder(string fileMark, string path, FTPClient client, string folder)

{

string[] dirs = client.Dir(path); //获取目录下的内容

client.ChDir(path); //改变目录

foreach (string dir in dirs)

{

string[] infos = dir.Split(' ');

string info = infos[infos.Length - 1].Replace("\r", "");

if (dir.StartsWith("d") && !string.IsNullOrEmpty(dir)) //为目录

{


if (!info.EndsWith(".") && !info.EndsWith("..")) //筛选出真实的目录

{

Directory.CreateDirectory(folder + "\\" + info);

GetFolder(fileMark, path + "/" + info, client, folder + "\\" + info);

client.ChDir(path);

}

}

else if (dir.StartsWith("-r")) //为文件

{

string file = folder + "\\" + info;

if (File.Exists(file))

{

long remotingSize = client.GetFileSize(info);

FileInfo fileInfo = new FileInfo(file);

long localSize = fileInfo.Length;


if (remotingSize != localSize) //短点续传

{

client.GetBrokenFile(info, folder, info, localSize);

}

}

else

{

client.GetFile(info, folder, info); //下载文件

Console.WriteLine("文件" + folder + info + "已经下载");

}

}

}


}

}

}
