Introduction
This is my maiden article in CodeProject. Here I shall be illustrating the usage of FTP in C# with an easy to use library that
I have coded. I have used the classes
FtpWebRequest
and FtpWebResponse
from the namespace System.Net
,
and they are sealed classes (cannot be inherited).
I have currently implemented these functions of FTP:
- listing files, listing directories
- uploading, downloading files
- creating/deleting directories and deleting files
Internals of the T-FTP class
The FtpModeUsePassive,CurrentDirectory
, FtpServer
, FtpPassword,FtpUserName
are the properties which represent the server name,
FTP user, and FTP password,and mode name(boolean type) namely passive and acticve.
public bool FtpModeUsePassive
{
get;
set;
}
public string CurrentDirectory
{
get;
set;
}
public string FtpServer
{
get;
set;
}
public string FtpUserName
{
get;
set;
}
public string FtpPassword
{
get;
set;
}
Remove files/directories and make new directories
We create the instance of FtpWebRequest
class with the FTP URL for the particular file or directory.
Eg., if the file is in
ftp://2shar.servehttp.com/httpdocs/myfiles/ then the corresponding URL would be as follows in the code:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + FtpServer + serverUri));
Next, reqFTP.Credentials
property takes object of class NetworkCredential
created with the constructor specifying the username and password as
arguments (we can also specify domain name in the constructor of NetworkCredential
).
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
The KeepAlive
property specifies whether the connection has to be left open after the corresponding process by default the value is true
.
UseBinary
property specifies the mode of FTP operation you can opt for either binary or ascii mode.
Each has its scenario in cases where you concerned with mostly text files and documents with ascii format texts you can initialise the property to false
while if you have to transfer files such as media or pictures or any zip files where binary streams of data are involved its better to opt for binary that is set property to true
.
In case of file upload there is a ContentLength
property that has to be set with the length of the file that you are uploading.
FileInfo
class provides you with the way to do that FileInfo
class has property Length (gives us the size of the file),
Name
(gives the name of the
file), FullName
(full path for the file).
Method
property of FtpWebRequest
gives us the purpose of the request( whether you want to create a directory delete a directory or a file).
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Method = WebRequestMethods.Ftp.RemoveDirectory;
Now we get the response for the FtpWebRequest
and place it in the
FtpWebRespnse
object the response.StatusDescription
gives us the information about the status
of the FTP request which can be passed to the caller any exceptions can be handled by using a try catch block and can return the exception to the caller.
public override string FtpMakeDirectory(string serverUri)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + FtpServer + serverUri));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = false;
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.MakeDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return "error-" + SomeException.Message.ToString();
}
}
public override string FtpRemoveDirectory(string serverUri)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + FtpServer + serverUri));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = false;
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.RemoveDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return "error-" + SomeException.Message.ToString();
}
}
File Upload and Download
When an user is downloading a file one has to create the instance of FtpWebRequest
class with the FTP URL for the particular file (e.g., if the file
is in ftp://2shar.servehttp.com/httpdocs/myfile.zip then the corresponding
URL would be as follows in the code.
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url + fileInf.Name));
Next, request.Credentials
property takes object of class NetworkCredential
created with the constructor specifying the username
and password as arguements (we can also specify domain name in the constructor of
NetworkCredential
).
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
The KeepAlive
property specifies whether the connection has to be left open after the corresponding process by default the value is true
.
UseBinary
property specifies the mode of FTP operation you can opt for either binary or
ASCII mode. Each has its scenario in cases where you concerned with
mostly text files and documents with ascii format texts you can initialise the property to false
while if you have to transfer files such as media or pictures
or any zip files where binary streams of data are involved its better to opt for binary that is set property to true
.
In case of file upload there is a ContentLength
property that has to be set with the length of the file that you are uploading.
The FileInfo
class provides you with the way to do that FileInfo
class has property
Length
(gives us the size of the file), Name
(gives the name of the file), FullName
(full path for the file).
Method
property of FtpWebRequest
gives us the purpose of the request (whether you want to upload, download or delete etc..)
request.Method = WebRequestMethods.Ftp.DownloadFile;
When we are downloading we initialize a new instance of the FileStream
class with the specified path, creation mode, and write permission.
FileStream fileStreamObject = new FileStream(downloadPath + fileInf.Name, FileMode.Create, FileAccess.Write);
We can get the size of the download file using the FtpWebRequest.Method
by setting the property to WebRequestMethods.Ftp.GetFileSize
FtpFileSize()
does the job in this case. The response to the request created would give the size of file.
By taking a size/100 as the size of the byte buffer which we can use to read from the response stream and will be
helpful to show the status and time of download.
We check the downloadFile
event to be not equal to null so that there
wouldn't be any unwanted behavior at run time due to event not being initialised by the user.
long tempLength = FtpFileSize("ftp://" + FtpServer + fileInf.ToString());
byte[] bufferByte = new byte[tempLength / 100];
int contentLength;
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
long tempLength1 = tempLength;
while (contentLength != 0)
{
fileStreamObject.Write(bufferByte, 0, contentLength);
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
tempLength -= contentLength;
if (tempLength > 0)
{
if (downloadFile != null)
{
downloadFile(tempLength1, tempLength);
}
}
}
Then we can read from the response stream and write the bytes that are read into the
filestream
object.
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
fileStreamObject.Write(bufferByte, 0, contentLength);
Once we have completely read from the response stream we will close the filestream
object and return the status of the response object to inform the caller about the status
of his request (i.e., whether the file has been downloaded or not).
fileStreamObject.Close();
responseStream.Close();
return response.StatusDescription.ToString();
public override event DisplayDownloadDelegate downloadFile;
public override event DisplayUploadDelegate uploadFile;
public override event CollectFilesDelegate displayCollectFiles;
public override event CollectDirectoryDelegate displayCollectDirectory;
The events and delegates for the upload and download are given above, this approach is used to implement the subscriber-publisher design where
the tftp.dll has published set of events namely uploadFile
and downloadFile
which corresponds to type of delegates DisplayUploadDelegate
and DisplayDownloadDelegate
.
Now a person using the DLL file can subscribe to the event by using a function of his own function which should also has to be of the delegate type DisplayUploadDelegate
and DisplayDownloadDelegate
.
These functions of the user will be called whenever the event is raised. If you look at the code of download you can notice that we are raising the event in FtpFileDownload
function downloadFile(len1,len)
after reading each set of bytes from the response stream doing so we are calling the subscriber function that the person
using the dll has written.
The functions that handle the download (FtpFileDownload
) and upload (FtpFileUpload
) are listed below.
public override string FtpFileUpload(string fileName, string url)
{
try
{
FileInfo fileInf = new FileInfo(fileName);
string uri = "ftp://" + FtpServer + "/" + url + fileInf.Name;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url + fileInf.Name));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
request.ContentLength = fileInf.Length;
long buffLength = fileInf.Length / 100;
byte[] bufferByte = new byte[buffLength];
int contentLength;
FileStream fileStreamObject = fileInf.OpenRead();
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
Stream streamObject = request.GetRequestStream();
contentLength = fileStreamObject.Read(bufferByte, 0, (int)buffLength);
long tempLength = fileStreamObject.Length;
while (contentLength != 0)
{
streamObject.Write(bufferByte, 0, contentLength);
contentLength = fileStreamObject.Read(bufferByte, 0, (int)buffLength);
tempLength -= contentLength;
if (tempLength > 0)
{
if (uploadFile != null)
{
uploadFile(fileStreamObject.Length, tempLength);
}
}
}
streamObject.Close();
fileStreamObject.Close();
return resp.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
public override long FtpFileSize(string url)
{
FtpWebRequest reqSize = (FtpWebRequest)FtpWebRequest.Create(new Uri(url));
reqSize.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
reqSize.Method = WebRequestMethods.Ftp.GetFileSize;
reqSize.UseBinary = true;
reqSize.UsePassive = FtpModeUsePassive;
FtpWebResponse respSize = (FtpWebResponse)reqSize.GetResponse();
respSize = (FtpWebResponse)reqSize.GetResponse();
long size = respSize.ContentLength;
respSize.Close();
return size;
}
public override string FtpFileDownload(string fileUrl, string downloadPath)
{
try
{
FileInfo fileInf = new FileInfo(fileUrl);
string uri = "ftp://" + FtpServer + "/httpdocs/" + fileInf.Name;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + fileInf.ToString()));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.UseBinary = true;
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse) request.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream fileStreamObject = new FileStream(downloadPath + fileInf.Name, FileMode.Create, FileAccess.Write);
long tempLength = FtpFileSize("ftp://" + FtpServer + fileInf.ToString());
byte[] bufferByte = new byte[tempLength / 100];
int contentLength;
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
long tempLength1 = tempLength;
while (contentLength != 0)
{
fileStreamObject.Write(bufferByte, 0, contentLength);
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
tempLength -= contentLength;
if (tempLength > 0)
{
if (downloadFile != null)
{
downloadFile(tempLength1, tempLength);
}
}
}
fileStreamObject.Close();
responseStream.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
File and directory List
I will explain the directory retrieval now. First, we have to create the instance of
the FtpWebRequest
class with the FTP URL for the particular fdirectory (e.g., if the directory
is ftp://2shar.servehttp.com/httpdocs/, then the corresponding URL for the request would be as follows.
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url));
Next, reqFTP.Credentials
property takes object of class NetworkCredential
created with the constructor specifying the username and password as
arguments (we can also specify domain name in the constructor of NetworkCredential
).
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
KeepAlive property specifies whether the connection has to be left open after the corresponding process by default the value is true
.
UseBinary
property specifies the mode of FTP operation you can opt for either binary or
ASCII mode.
Each has its scenario in cases where you concerned with mostly text files and documents with ascii format texts you can initialise the property to
false
while if you have to transfer files such as media or pictures or any zip files where binary streams of data are involved its
better to opt for binary that is set property to true
.
FileInfo
class provides you with the way to do that FileInfo
class has property Length (gives us the size of the file),
Name
(gives the name of the
file), FullName
(full path for the file).
Method
property of FtpWebRequest
gives us the purpose of the request( whether you want to upload, download or delete or list files or directory etc..)
We use WebRequestMethods.Ftp.ListDirectoryDetails
so that we can display the details of creation date and size associated with each files,
if only the file name is to be displayed then we can use WebRequestMethods.Ftp.ListDirectory
.
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
Thereafter we get the response for the FTP request and store it in a FtpWebResponse
object (response
) and get the stream for the response object
and read the stream with help of a StreamReader
object.The code is given below.
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader readerObject = new StreamReader(responseStream);
We can carefully index out the directory name and directory creation date
from the string read by the StreamReader
class use methods of String class
namely String.IndexOf(string value,int startindex)
use String.subString(int startindex,int length)
.
if (processString.IndexOf("<DIR>", 0) != -1)
{
string processedString = RemoveWhiteSpaces(processString);
dirdate = processedString.Substring(0, processedString.IndexOf("<DIR>", 0));
dirname = processedString.Substring(processedString.IndexOf("<DIR>", 0) + 5, processedString.Length - (processedString.IndexOf("<DIR>", 0) + 5));
listDirectoryCollection.Add(dirname, dirdate);
displayCollectDirectory(dirname, dirdate);
}
Now we can get the status of operation by returning the status of response object.
return response.StatusDescription.ToString();
The functions that handle the list directories (FtpListDirectories
) and list files (FtpListFiles
) are listed below.
public override string[] ResolveFiles(string filesString)
{
string resultString = string.Empty;
char[] arrayOfCharacters = filesString.ToCharArray();
bool flags = false;
foreach (char singleCharacter in arrayOfCharacters)
{
if (singleCharacter == ' ')
{
if (flags == false)
{
resultString = resultString + "#";
}
flags = true;
}
else
{
resultString = resultString + singleCharacter;
flags = false;
}
}
char[] seperatorCharacter = { '#' };
string[] returnStringArray = resultString.Split(seperatorCharacter);
return returnStringArray;
}
public override string RemoveWhiteSpaces(string processString)
{
string resultString = string.Empty;
char[] arrayOfCharacters = processString.ToCharArray();
foreach (char singleCharacter in arrayOfCharacters)
{
if (singleCharacter != ' ')
{
resultString = resultString + singleCharacter.ToString();
}
}
return resultString;
}
public override string FtpListDirectories(string url)
{
listDirectoryCollection = new Dictionary<string, string>(100000);
try
{
string uri = FtpServer + url;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = true;
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UseBinary = true;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string processString;
string dirname, dirdate;
processString = reader.ReadLine();
while (processString != null)
{
if (processString.IndexOf("<DIR>", 0) != -1)
{
string processedString = RemoveWhiteSpaces(processString);
dirdate = processedString.Substring(0, processedString.IndexOf("<DIR>", 0));
dirname = processedString.Substring(processedString.IndexOf("<DIR>", 0) + 5, processedString.Length - (processedString.IndexOf("<DIR>", 0) + 5));
listDirectoryCollection.Add(dirname, dirdate);
displayCollectDirectory(dirname, dirdate);
}
else
{
}
processString = reader.ReadLine();
}
reader.Close();
response.Close();
return "ok";
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
public override string FtpListFiles(string url)
{
listFileCollection = new Dictionary<string, string>(100000);
try
{
string uri = "ftp://" + FtpServer + url;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.KeepAlive = true;
request.UsePassive = FtpModeUsePassive;
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UseBinary = true;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader readerObject = new StreamReader(responseStream);
string processString;
string dirname, dirdate;
processString = readerObject.ReadLine();
while (processString != null)
{
if (processString.IndexOf("<DIR>", 0) != -1)
{
string processedString = RemoveWhiteSpaces(processString);
dirdate = processedString.Substring(0, processedString.IndexOf("<DIR>", 0));
dirname = processedString.Substring(processedString.IndexOf("<DIR>", 0) + 5, processedString.Length - (processedString.IndexOf("<DIR>", 0) + 5));
}
else
{
string[] processedString = ResolveFiles(processString);
listFileCollection.Add(processedString[3].ToString(), (Int32.Parse(processedString[2].ToString()) / 1024).ToString());
displayCollectFiles(processedString[3].ToString(), (Int32.Parse(processedString[2].ToString()) / 1024).ToString(), processedString[0] + "-" + processedString[1]);
}
processString = readerObject.ReadLine();
}
readerObject.Close();
response.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
Using T-FTP Library in your project
In the introduction tftp library interiors and working has been demonstrated now I shall explain on how you can hook this up with your project.
Properties
property name | semantics | datatype |
FtpUserName | represents the ftp username | string |
FtpServer | represents ftp
address | string |
FtpPassword | represents ftp user password | string |
FtpModeUsePassive | select betwen two modes | bool |
Example
TusharFtp.FtpClass ftpObject = new TusharFtp.FtpHelperClass();
ftpObject.FtpServer = servers;
ftpObject.FtpUserName = users;
ftpObject.FtpPassword = pass;
ftpObject.FtpModeUsePassive = true;
1. Upload (with the status of upload)
If uploadme
is the name of your function that is subscribing to the event upload_file
.
Variables a
and b
represents total size in bytes and size yet to be downloaded/uploaded for the file.
static void UploadMe(long totalLength, long currentLength)
{
Console.WriteLine(currentLength + " out of " + totalLength +"has been left to downloaded so far");
}
ftpObject.uploadFile += new tftp.tftp.DisplayUploadDelegate(UploadMe);
Console.WriteLine( ftpObject.FtpFileUpload("e:\\splits.zip","/httpdocs/"));
Similarly for the download function.
2. Listing directories
If FtpListDirectories
is the name of your function that is subscribing to the event displayCollectDirectory
.
FtpListDirectories
is the function in the DLL that gives you the list of the directories ,the parameters of the function represent name of the directory and creation date of the directory.
static void ListDirectories(string directoryName,string directoryCreateDate)
{
Console.WriteLine("directory name= "+directoryName+" directory creation date= "+directoryCreateDate);
}
ftpObject.displayCollectDirectory += new TusharFtp.CollectDirectoryDelegate(ListDirectories);
ftpObject.FtpListDirectories("/httpdocs/");
Similarly for listing files, we can use the FtpListFiles()
function.
3. Listing files
If FtpListFiles
is the name of your function that is subscribing to the event displayCollectFiles
.
FtpListFiles
is the function in the DLL that gives you the list of the files, the parameters of the function represent name of the file,
the size of the file and creation date of the file.
static void ListFiles(string fileName,string fileSize,string fileCreateDate)
{
Console.WriteLine("file name= "+fileName+" file size= "+fileSize+" file creation date "+fileCreateDate);
}
ftpObject.displayCollectFiles += new TusharFtp.CollectFilesDelegate(listdir);
ftpObject.FtpListFiles("/httpdocs/");
4. Make directory and delete directory and delete files
These functions have string return types which informs about the status of the operation. FtpMakeDirectory
, FtpRemoveDirectory
,FtpDeleteFile
represents the three functions for making directory, deleting directory, and deleting file.
string makeDirectoryStatus = ftpObject.FtpMakeDirectory("httpdocs/tftp");
string removeStatus = ftpObject.FtpRemoveDirectory("httpdocs/tftp");
string deleteStatus=ftpObject.FtpDeleteFile("httpdocs/splits.zip");
Points of interest
Thanks for reading through, you can learn more about the FTPWebRequest class
in MSDN and FTPWebResponse class in MSDN.