Introduction
An addition to the Microsoft .NET framework 2.0 to 1.x is the support for FTP. All these days, we had to rely on 3rd party libraries which pretty well suited most of our needs, but for sure, there is an extra pleasure using the .NET Framework library classes. The code included is not designed to be a full fledged reusable library, but rather an easy to use and reusable pieces of code which is easily comprehensible and can be reused and tweaked to fit your specific needs. Therefore, the code for each functionality (upload, download, delete, etc.) can be easily picked up separately and reused. The main motive behind this article was the unavailability of .NET 2.0 FTP sample codes and their usage in C#; may be because it's a new entrant to the .NET scenario, or the third party implementations available were working pretty well, that this area of the .NET 2.0 library haven't got enough focus.
Background
I started working on this FTP module as part of my official work, but the requirement soon changed and I had to do it for .NET 1.1. So, I haven't travelled deeper into the rabbit hole. But I believe this gives a good, instant start for using the FTP support in .NET 2.0.
Using the Code
Don't forget to add the following directive:
using System.Net;
using System.IO;
The following steps can be considered as a generic procedure of getting an FTP request executed using FtpWebRequest
object:
- Create an
FtpWebRequest
object over an FTP server URI - Set the FTP method to execute (
upload
, download
, etc.) - Set options (SSL support, transfer as binary/not, etc.) for the FTP
webrequest
- Set the login credentials (
username
, password
) - Execute the request
- Receive the response stream (if required)
- Close the FTP Request, in addition to any open streams
One point to watch out while coding for any FTP application is to have the settings for the FTP request proper to suit the FTP server and its specific configurations. FtpWebRequest
object exposes many properties to have these settings in place.
The sample for the upload
functionality is as follows:
First, a URI is created which represents the FTP address along with the filename (directory structure included). This URI is used to create the FtpWebRequest
instance.
Then, properties of the FtpWebRequest
object are set, which determines the settings for the FTP request. Some of its important properties are:
Credentials
- specifies the username and password to login to the FTP server. KeepAlive
- specifies if the control connection should be closed or not after the request is completed. By default, it is set to true
. UseBinary
- denotes the datatype for file transfers. The 2 modes of file transfer in this case are Binary
and ASCII
. At bit level, both vary in the 8th bit of a byte. ASCII uses 8th bit as insignificant bit for error control, whereas, for binary, all the 8 bits are significant. So take care when you go for the ASCII transmission. To be simple, all those files that open and read well in Notepad are safe as ASCII. Executables, formatted docs, etc. should be sent using binary mode. BTW, sending ASCII files as binary works fine most of the time. UsePassive
- specifies to use either active or passive mode. Earlier, active FTP worked fine with all clients, but now a days, as most of the random ports will be blocked by firewall, the active mode may fail. The passive FTP is helpful in this case. But still, it causes issues at the server. The higher ports requested by client on server may also be blocked by firewall. But since FTP servers will need to make their servers accessible to the greatest number of clients, they will almost certainly need to support passive FTP. The reason why passive mode is considered safe is that, it ensures all data flow initiation comes from inside(client) the network rather than from the outside(server). Contentlength
- setting this property is useful for the server we request to but is not of much use for us(client), because FtpWebRequest
usually ignores this property value, so it will not be available for our use in most of the cases. But if we set this property, the FTP server will get an idea in advance about the size of the file it should expect (in case of upload) Method
- denotes what action (command) to take in the current request (upload
, download
, filelist
, etc.) It is set a value defined in the WebRequestMethods.Ftp
structure.
private void Upload(string filename)
{
FileInfo fileInf = new FileInfo(filename);
string uri = "ftp://" + ftpServerIP + "/" + fileInf.Name;
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(
"ftp://" + ftpServerIP + "/" + fileInf.Name));
reqFTP.Credentials = new NetworkCredential(ftpUserID,
ftpPassword);
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
reqFTP.UseBinary = true;
reqFTP.ContentLength = fileInf.Length;
int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
the file to be uploaded
FileStream fs = fileInf.OpenRead();
try
{
Stream strm = reqFTP.GetRequestStream();
contentLen = fs.Read(buff, 0, buffLength);
while (contentLen != 0)
{
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
}
strm.Close();
fs.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Upload Error");
}
}
Above is a sample code for FTP Upload (PUT
). The underlying sub command used is STOR
. Here, an FtpWebRequest
object is made for the specified file on the FTP server. Different properties are set for the request namely Credentials
, KeepAlive
, Method
, UseBinary
, ContentLength
. The file in our local machine is opened and the contents are written to the FTP request stream. Here, a buffer of size 2KB is used as an appropriate size suited for upload of larger or smaller files.
private void Download(string filePath, string fileName)
{
FtpWebRequest reqFTP;
try
{
FileStream outputStream = new FileStream(filePath +
"\\" + fileName, FileMode.Create);
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" +
ftpServerIP + "/" + fileName));
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID,
ftpPassword);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
long cl = response.ContentLength;
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[bufferSize];
readCount = ftpStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
outputStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
}
ftpStream.Close();
outputStream.Close();
response.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Above is a sample code for download of file from the FTP server. Unlike the Upload
functionality described above, Download
would require the response stream, which will contain the content of the file requested.
Here, the file to download is specified as part of the URI which in turn is used for the creation of the FtpWebRequest
object. To 'GET
' the file requested, get the response of the FtpWebRequest
object using GetResponse()
method. This new response object built provides the response stream which contain the file content as stream, which you can easily convert to a file stream to get the file in place.
Note: We have the flexibility to set the location and name of the file under which it is to be saved on our local machine.
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
FtpWebRequest reqFTP;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(
"ftp://" + ftpServerIP + "/"));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID,
ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = reqFTP.GetResponse();
StreamReader reader = new StreamReader(response
.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
result.Remove(result.ToString().LastIndexOf('\n'), 1);
reader.Close();
response.Close();
return result.ToString().Split('\n');
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
downloadFiles = null;
return downloadFiles;
}
}
Above is a sample block of code for getting the file list on the FTP server. The URI is built specifying the FTP server address/name and the required path if any. In the above example, the root folder is specified for the creation of the FtpWebRequest
object. Here, the response stream is used for the creation of a StreamReader
object, which has the whole list of file names on the server separated by "\r\n
" which is newline and carriagereturn together. You can get the whole file list ("\r\n
" separated) using the ReadToEnd()
method of the StreamReader
object. The above implementation reads each file name and creates a StringBuilder
object by appending each file name. The resultant StringBuilder
object is split into a string
array and returned. I am sure there are better ways to do it. A better way could be to remove the whole '\r
' instances from the whole list (returned by <<StreamReader>>.ReadToEnd())
) and split the resultant string
using '\n
' delimiter. Anyway, I didn't want to spend more of my energy and time pondering over it ;-).
The implementations for Rename
, Delete
, GetFileSize
, FileListDetails
, MakeDir
are very similar to the above pieces of code and the attached code is easily comprehensible.
Note: For renaming, the new name can be assigned to the RenameTo
property of FtpWebRequest
object. For MakeDirectory
, the name of the new directory can be specified as part of the URI used to create FtpWebRequest
object.
Points of Interest
Please take NOTE of the following points while coding in this area:
- Unless the
EnableSsl
property is true
, all data and commands, including your user name and password information, are sent to the server in clear text. Anyone monitoring network traffic can view your credentials and use them to connect to the server. If you are connecting to an FTP server that requires credentials and supports Secure Sockets Layer (SSL), you should set EnableSsl
to true
. - If you do not have the proper
WebPermission
to access the FTP resource, a SecurityException
exception is thrown. - Requests are sent to the server by calling the
GetResponse
method. When the requested operation completes, an FtpWebResponse
object is returned. The FtpWebResponse
object provides the status of the operation and any data downloaded from the server. That is,
StatusCode
property of FtpWebResponse
object provides the latest status code returned by the FTP server.
StatusDescription
property of FtpWebResponse
object provides the description of the status code returned.
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.