Ultimate Guide to Working With FTP using C#How to use the FtpWebRequest and FtpWebResponse classes to to retrieve a directory listing, download files, upload files and delete files.
I'm going to create a utility class during this tutorial which contains a series of methods to perform using FTP. You can copy and paste into your project, or adapt to suit your needs.
I'm basing this on a console application with an extra class file called FTPUtility.cs. All this code goes inside that file.
Creating the FTPClient Class
The first thing I have done is to create a set of private fields that need to be populated from the constructor.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
namespace Utils
{
public class FTPClient
{
/ The hostname or IP address of the FTP server
private string _remoteHost;
/ The remote username
private string _remoteUser;
/ Password for the remote user
private string _remotePass;
}
}
The constructor for this class takes in the connection properties for the remote host.
public FTPClient(string remoteHost, string remoteUser, string remotePassword)
{
_remoteHost = remoteHost;
_remoteUser = remoteUser;
_remotePass = remotePassword;
}
FTP using C# - Directory Listing Function
The first thing we are going to look at is establishing a connection to the server and retrieving a file list.
public List<string> DirectoryListing()
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
List<string> result = new List<string>();
while (!reader.EndOfStream)
{
result.Add(reader.ReadLine());
}
reader.Close();
response.Close();
return result;
}
If I run this over my test site with the following code:
namespace FTPTestApplication
{
class Program
{
static void Main(string[] args)
{
Utils.FTPClient client = new Utils.FTPClient("ftp:/localhost", "ftpUser", "ftpPass");
List<string> files = client.DirectoryListing();
foreach (string s in files)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
}
}
The result is:
.cshrc .imap .login .login_conf .mail_aliases .mailrc .profile .rhosts .shrc backup boxes log_config public_html www_logs
Now the next logical step is to navigate to a folder, this can be done by amending the parameter to the WebRequest.Create method. I have created an overloaded method so that we can browse the root or into a given folder.
public List<string> DirectoryListing()
{
return DirectoryListing(string.Empty);
}
public List<string> DirectoryListing(string folder)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + folder);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
List<string> result = new List<string>();
while (!reader.EndOfStream)
{
result.Add(reader.ReadLine());
}
reader.Close();
response.Close();
return result;
}
I can now add directory information to the original call to look inside a folder.
Utils.FTPClient client = new Utils.FTPClient("ftp:/localhost/public_html/", "ftpUser", "ftpPass");
Downloading a File with our FTPClient
The next task is to download a file from the server to our PC. This is done in much the same way as directory listings.
public void Download(string file, string destination)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + file);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
StreamWriter writer = new StreamWriter(destination);
writer.Write(reader.ReadToEnd());
writer.Close();
reader.Close();
response.Close();
}
To call this method use:
Utils.FTPClient client = new Utils.FTPClient("ftp:/localhost/public_html/", "ftpUser", "ftpPass");
client.Download("test.zip", "c:test.zip");
Hopefully, you can start to see a pattern forming when using FtpWebRequest methods. In fact, all the code is pretty similar regardless of what action you are performing. The WebRequestMethods.Ftp enum contains a list of actions you can perform. These include:
- AppendFile - Append a file to an existing file on an FTP server (FTP APPE)
- DeleteFile - Delete a file on an FTP server (FTP DELE)
- DownloadFile - Download a file from an FTP server (FTP RETR)
- GetFileSize - Retrieve the size of a file on an FTP server (FTP SIZE)
- ListDirectory - Gets a short listing of the files on an FTP server (FTP NLIST)
- ListDirectoryDetails - Gets a detailed listing of the files on an FTP server (FTP LIST)
- MakeDirectory - Creates a directory on an FTP server (FTP MKD)
- RemoveDirectory - Method that removes a directory (FTP RM)
- Rename - Renames a directory (FTP RENAME)
- UploadFile - Uploads a file to an FTP server (FTP STOR)
- UploadFileWithUniqueName - Uploads a file with a unique name to an FTP server (FTP STOU)
Uploading a File through FTPClient
The final example I am going to show is how to upload a file to the server. This method differs slightly as we need to create a StreamReader to read the source file.
public void UploadFile(string FullPathFilename)
{
string filename = Path.GetFileName(FullPathFilename);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + filename);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
StreamReader sourceStream = new StreamReader(FullPathFilename);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
requestStream.Close();
sourceStream.Close();
}
And that's all there is to it.
Just a few points to remember:
- WebRequest.Create takes the full URL including path and file name. To work with a file specify the full path name e.g. ftp:/localhost/folder/test/myfile.zip.
- To work with a folder/directory, specify the full path e.g. ftp:/localhost/folder/test/
- You cannot upload a file to ftp:/localhost/folder/test/, you have to specify the filename when you create the WebRequest.
FTPClient Code in Full
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
namespace Utils
{
public class FTPClient
{
/ The hostname or IP address of the FTP server
private string _remoteHost;
/ The remote username
private string _remoteUser;
/ Password for the remote user
private string _remotePass;
public FTPClient(string remoteHost, string remoteUser, string remotePassword, bool debug)
{
_remoteHost = remoteHost;
_remoteUser = remoteUser;
_remotePass = remotePassword;
}
// <summary>
// Get a list of files and folders on the FTP server
// </summary>
// <returns></returns>
public List<string> DirectoryListing()
{
return DirectoryListing(string.Empty);
}
// <summary>
// List files and folders in a given folder on the server
// </summary>
// <param name="folder"></param>
// <returns></returns>
public List<string> DirectoryListing(string folder)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + folder);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
List<string> result = new List<string>();
while (!reader.EndOfStream)
{
result.Add(reader.ReadLine());
}
reader.Close();
response.Close();
return result;
}
// <summary>
// Download a file from the FTP server to the destination
// </summary>
// <param name="filename">filename and path to the file, e.g. public_html/test.zip</param>
// <param name="destination">The location to save the file, e.g. c:test.zip</param>
public void Download(string filename, string destination)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + filename);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
StreamWriter writer = new StreamWriter(destination);
writer.Write(reader.ReadToEnd());
writer.Close();
reader.Close();
response.Close();
}
// <summary>
// Remove a file from the server.
// </summary>
// <param name="filename">filename and path to the file, e.g. public_html/test.zip</param>
public void DeleteFileFromServer(string filename)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + filename);
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
}
// <summary>
// Upload a file to the server
// </summary>
// <param name="source">Full path to the source file e.g. c:test.zip</param>
// <param name="destination">destination folder and filename e.g. public_html/test.zip</param>
public void UploadFile(string source, string destination)
{
string filename = Path.GetFileName(source);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + destination);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
StreamReader sourceStream = new StreamReader(source);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
requestStream.Close();
sourceStream.Close();
}
}
}