FTP Client library in C# (轉)

worldblog發表於2007-12-07
FTP Client library in C# (轉)[@more@]這是個用寫的客戶端庫,可編譯成DLL使用,
支援所有的FTP命令、檔案上下傳,

/*
FTPFactory.cs
Better view with tab space=4
use the following line to compile
csc /target:library /out:FTPLib.dll /r:System.DLL FTPFactory.cs
*/


using System;
using System.Net;
using System.IO;
using System.Text;
using System.Net.Sockets;

namespace FtpLib {

public class FTPFactory {

private string remoteHost,remotePath,remoteUser,remotePass,mes;
private int remotePort,bytes;
private Socket clientSocket;

private int retValue;
private Boolean de;
private Boolean logined;
private string reply;

private static int BLOCK_SIZE = 512;

Byte[] buffer = new Byte[BLOCK_SIZE];
Encoding ASCII = Encoding.ASCII;

public FTPFactory() {

remoteHost = "localhost";
remotePath = ".";
remoteUser = "anonymous";
remotePass = "ftpclient@ospreyindia.com";
remotePort = 21;
debug = false;
logined = false;

}
public void setRemoteHost(string remoteHost) {
this.remoteHost = remoteHost;
}
public string getRemoteHost() {
return remoteHost;
}
public void setRemotePort(int remotePort) {
this.remotePort = remotePort;
}
public int getRemotePort() {
return remotePort;
}
public void setRemotePath(string remotePath) {
this.remotePath = remotePath;
}
public string getRemotePath() {
return remotePath;
}
public void setRemoteUser(string remoteUser) {
this.remoteUser = remoteUser;
}
public void setRemotePass(string remotePass) {
this.remotePass = remotePass;
}
public string[] getFileList(string mask) {

if(!logined) {
login();
}

Socket cSocket = createDataSocket();

sendCommand("NLST " + mask);

if(!(retValue == 150 || retValue == 125)) {
throw new IOException(reply.Substring(4));
}

mes = "";

  while(true) {
  int bytes = cSocket.Receive(buffer, buffer.Length, 0);
  mes += ASCII.GetString(buffer, 0, bytes);
  if(bytes < buffer.Length) {
break;
}
}

char[] seperator = {'n'};
string[] mess = mes.Split(seperator);

cSocket.Close();

readReply();
if(retValue != 226) {
throw new IOException(reply.Substring(4));
}
return mess;

}
public long getFileSize(string fileName) {

if(!logined) {
login();
}

sendCommand("SIZE " + fileName);
long size=0;

if(retValue == 213) {
size = reply.Substring(4).ToInt64();
}else {
throw new IOException(reply.Substring(4));
}
return size;

}
public void login() {

clientSocket = new Socket(Addresamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
IPEndPoint ep = new IPEndPoint(.Resolve(remoteHost), remotePort);
int i = clientSocket.Connect(ep);
if( i != 0 ) {
throw new IOException("Couldn't connect to remote server");
}

readReply();
if(retValue != 220) {
close();
throw new IOException(reply.Substring(4));
}
if(debug)
Console.WriteLine("USER "+remoteUser);
sendCommand("USER "+remoteUser);
if( !(retValue == 331 || retValue == 230) ) {
cleanup();
throw new IOException(reply.Substring(4));
}
if( retValue != 230 ) {
if(debug)
Console.WriteLine("PASS xxx");

sendCommand("PASS "+remotePass);
if( !(retValue == 230 || retValue == 202) ) {
cleanup();
throw new IOException(reply.Substring(4));
}
}

logined = true;
Console.WriteLine("Connected to "+remoteHost);

chdir(remotePath);

}
public void setBinaryMode(Boolean mode) {

if(mode) {
sendCommand("TYPE I");
}else {
sendCommand("TYPE A");
}
if (retValue != 200) {
throw new IOException(reply.Substring(4));
}
}
public void (string fileName) {
download(fileName,false);
}
public void download(string fileName,Boolean resume) {


if(!logined) {
login();
}

setBinaryMode(true);
long totalSize=0;
try{
totalSize = getFileSize(fileName);
}catch(Exception) {
throw new Exception("File Not Found "+fileName);
}


Console.WriteLine("Downloading file "+fileName+" from "+remoteHost + "/"+remotePath);

if(!File.FileExists(fileName)) {
Stream st = File.Create(fileName);
st.Close();
}

FileStream output = new FileStream(fileName,FileMode.Open);

Socket cSocket = createDataSocket();

long offset = 0;

if(resume) {

offset = output.Length;

if(offset > 0 ) {
  sendCommand("REST "+offset);
  if(retValue != 350) {
    //throw new IOException(reply.Substring(4));
    //Server may not support resuming.
    offset = 0;
   }
  }

  if(offset > 0) {
   if(debug) {
   Console.WriteLine("seeking to " + offset);
}
   long npos = output.Seek(offset,SeekOrigin.Begin);
   Console.WriteLine("new pos="+npos);
  }
}

sendCommand("RETR " + fileName);

if(!(retValue == 150 || retValue == 125)) {
throw new IOException(reply.Substring(4));
}

 float iCnt = 0;
 float per = 0, oldPer = 1;

  while(true) {

  bytes = cSocket.Receive(buffer, buffer.Length, 0);
  output.Write(buffer,0,bytes);

// Showing the progress. 1..50
iCnt += bytes;
per = (int) ( (iCnt / totalSize) * 100 );
if( per != oldPer && per % 2 == 0 ) {
Console.Write(".");
oldPer = per;
}

  if(bytes < buffer.Length) {
break;
}
}

output.Close();
cSocket.Close();
Console.WriteLine("");

readReply();

if( !(retValue == 226 || retValue == 250) ) {
throw new IOException(reply.Substring(4));
}

}
public void (string fileName) {
upload(fileName,false);
}
public void upload(string fileName,Boolean resume) {

if(!logined) {
login();
}

Socket cSocket = createDataSocket();
long offset=0;

if(resume) {

try {

setBinaryMode(true);
offset = getFileSize(fileName);

}catch(Exception) {
offset = 0;
}
}

if(offset > 0 ) {
sendCommand("REST " + offset);
if(retValue != 350) {
//throw new IOException(reply.Substring(4));
//Remote server may not support resuming.
offset = 0;
}
}

sendCommand("STOR "+fileName);
if( !(retValue == 125 || retValue == 150) ) {
throw new IOException(reply.Substring(4));
}

 // open input stream to read  file
 FileStream input = new FileStream(fileName,FileMode.Open);

if(offset != 0){

 if(debug) {
Console.WriteLine("seeking to " + offset);
}
 input.Seek(offset,SeekOrigin.Begin);
}

 //for progress bar
 long totalSize = input.Length - offset;
 float iCnt = 0;
 int per = 0, oldPer = 1;
 Console.WriteLine("Uploading file "+fileName+" to "+remotePath);

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

cSocket.Send(buffer, bytes, 0);

 // Showing the progress. 1..50
iCnt += bytes;
per = (int) ( (iCnt / totalSize) * 100 );
if( per != oldPer && per % 2 == 0 ) {
Console.Write(".");
oldPer = per;
}
 }
 input.Close();

Console.WriteLine("");

cSocket.Close();

 readReply();
 if( !(retValue == 226 || retValue == 250) ) {
throw new IOException(reply.Substring(4));
}
}
public void deleteRemoteFile(string fileName) {

if(!logined) {
login();
}

sendCommand("DELE "+fileName);

if(retValue != 250) {
throw new IOException(reply.Substring(4));
}

}
public void renameRemoteFile(string oldFileName,string newFileName) {

if(!logined) {
login();
}

sendCommand("RNFR "+oldFileName);

if(retValue != 350) {
throw new IOException(reply.Substring(4));
}

// known problem
// rnto will not take care of existing file.
// i.e. It will overwrite if newFileName exist
sendCommand("RNTO "+newFileName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}

}
public void mkdir(string dirName) {

if(!logined) {
login();
}

sendCommand("MKD "+dirName);

if(retValue != 250) {
throw new IOException(reply.Substring(4));
}

}
public void rmdir(string dirName) {

if(!logined) {
login();
}

sendCommand("RMD "+dirName);

if(retValue != 250) {
throw new IOException(reply.Substring(4));
}

}
public void chdir(string dirName) {
if(dirName.Equals(".")) {
return;
}

if(!logined) {
login();
}

sendCommand("CWD "+dirName);

if(retValue != 250) {
throw new IOException(reply.Substring(4));
}

this.remotePath = dirName;

Console.WriteLine("Current directory is "+remotePath);

}
public void close() {
if( clientSocket != null ) {
sendCommand("QUIT");
}
cleanup();
Console.WriteLine("Closing...");
}
public void setDebug(Boolean debug) {
this.debug = debug;
}
 private void readReply() {
mes = "";
reply = readLine();
 retValue = reply.Substring(0,3).ToInt32();
  }
private void cleanup() {
if(clientSocket!=null) {
clientSocket.Close();
clientSocket = null;
}
logined = false;
}
private string readLine() {

  while(true) {
  bytes = clientSocket.Receive(buffer, buffer.Length, 0);
  mes += ASCII.GetString(buffer, 0, bytes);
  if(bytes < buffer.Length) {
break;
}
}

char[] seperator = {'n'};
string[] mess = mes.Split(seperator);
if(mes.Length > 2) {
  mes = mess[mess.Length-2];
}else {
mes = mess[0];
}
if(!mes.Substring(3,1).Equals(" ")) {
return readLine();
}
if(debug) {
for(int k=0;k < mess.Length-1;k++) {
Console.WriteLine(mess[k]);
}
}
return mes;
}
private void sendCommand(String command) {
Byte[] cmytes = Encoding.ASCII.GetBytes((command+"rn").ToCharArray());
clientSocket.Send(cmdBytes, cmdBytes.Length, 0);
readReply();
}
private Socket createDataSocket() {

sendCommand("PASV");

if(retValue != 227) {
throw new IOException(reply.Substring(4));
}

int index1 = reply.IndexOf('(');
int index2 = reply.IndexOf(')');
string ipData = reply.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 = ipData.Substring(i,1).ToChar();
if (Char.IsDigit(ch))
buf+=ch;
else if (ch != ',') {
throw new IOException("Malformed PASV reply: " + reply);
}

if (ch == ',' || i+1 == len) {
try {
parts[partCount++] = buf.ToInt32();
buf="";
}
catch (Exception) {
throw new IOException("Malformed PASV reply: " + reply);
}
}
}

string ipAddress = parts[0] + "."+ parts[1]+ "." +
parts[2] + "." + parts[3];

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

Socket s = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
IPEndPoint ep = new IPEndPoint(DNS.Resolve(ipAddress), port);

int sucess = s.Connect(ep);

if( sucess != 0 ) {
throw new IOException("Can't connect to remote server");
}

return s;
}

}
}


Following is the listing of a test program which uses this library


/*

File : Test.cs
Better view with tab space=4
use the following line to compile
csc.exe /t:exe /r:System.DLL /r:System.Net.DLL /r:FTPLib.dll /out:"Test.exe" "Test.cs"

*/
using System;
using FtpLib;

public class Test {

public static void Main() {

try {

Console.WriteLine("Starting...");

FTPFactory ff = new FTPFactory();
ff.setDebug(true);
ff.setRemoteHost("192.168.10.19");
ff.setRemoteUser("jaimon");
ff.setRemotePass("mathew");
ff.login();

string[] fileNames = ff.getFileList("*.*");
for(int i=0;i < fileNames.Length;i++) {
Console.WriteLine(fileNames[i]);
}
ff.download("Readme.zip",true);
ff.close();

}catch(Exception e) {
Console.WriteLine("Caught Error :"+e.Message);
}
}
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989336/,如需轉載,請註明出處,否則將追究法律責任。

相關文章