C# FluentFTP
last modified October 15, 2026
In this article we show how to work with FTP in C# using FluentFTP.
FluentFTP is an FTP and FTPS client for .NET. It supports many FTP
commands, file uploads and downloads, SSL/TLS connections, file hashing and
checksums, file permissions, and FTP proxies. The library provides a synchronous
FtpClient and an asynchronous AsyncFtpClient.
File Transfer Protocol (FTP) is a standard network protocol used for transferring computer files between a client and a server on a computer network. Clients and servers communicate with a set of FTP commands, such as DELE, RETR, or CWD.
$ dotnet add package FluentFTP
We add the package to the project. The examples were tested with FluentFTP 55.
Note that plain FTP sends credentials and data unencrypted. If the server
supports it, we should use FTPS, for instance by setting
con.Config.EncryptionMode = FtpEncryptionMode.Auto; before
connecting.
C# FluentFTP make directory
In the first example, we create a remote directory.
using FluentFTP;
var host = "example.com";
var username = "user7";
var passwd = "s$cret";
var path = "/web/test/";
using var con = new FtpClient(host, username, passwd);
con.Connect();
var ok = con.CreateDirectory(path);
if (ok) {
Console.WriteLine("directory successfully created");
} else {
Console.WriteLine("failed to create directory");
}
The program creates a new directory on the provided FTP server and prints a message.
var path = "/web/test/";
This is the name of the new directory.
using var con = new FtpClient(host, username, passwd); con.Connect();
We create a new FTP client and make a connection.
var ok = con.CreateDirectory(path);
A new directory is created with CreateDirectory. The method returns
a boolean value indicating whether the creation was successful.
if (ok) {
Console.WriteLine("directory successfully created");
} else {
Console.WriteLine("failed to create directory");
}
Depending on the returned value, we print a message to the console.
$ dotnet run directory successfully created
C# FluentFTP download file
A file is downloaded with the DownloadFile method.
using FluentFTP;
var host = "example.com";
var username = "user7";
var passwd = "s$cret";
var path = "/web/csharp/quest-pdf/index.html";
var baseName = Path.GetFileName(path);
using var con = new FtpClient(host, username, passwd);
con.Connect();
var status = con.DownloadFile(baseName, path,
FtpLocalExists.Overwrite, FtpVerify.Retry);
var msg = status switch {
FtpStatus.Success => "file successfully downloaded",
FtpStatus.Failed => "failed to download file",
_ => "unknown"
};
Console.WriteLine(msg);
The program downloads an index.html file from the FTP server. It prints a message about the outcome.
var status = con.DownloadFile(baseName, path,
FtpLocalExists.Overwrite, FtpVerify.Retry);
We download the file with DownloadFile. The first parameter is the
local path name, the second is the remote path name. The
FtpLocalExists.Overwrite option overwrites the local file if it
exists on disk. With the FtpVerify.Retry option we tell the client
to retry the download a few times if it fails. The method returns
FtpStatus.
var msg = status switch {
FtpStatus.Success => "file successfully downloaded",
FtpStatus.Failed => "failed to download file",
_ => "unknown"
};
Depending on the returned status value, we provide a message. Besides
Success and Failed, the method can also return
Skipped if the file was not downloaded.
$ dotnet run file successfully downloaded
C# FluentFTP upload file
A file is uploaded with the UploadFile method.
using FluentFTP;
var host = "example.com";
var username = "user7";
var passwd = "s$cret";
var rpath = "/web/test/index.html";
var lpath = "index.html";
using var con = new FtpClient(host, username, passwd);
con.Connect();
var status = con.UploadFile(lpath, rpath, FtpRemoteExists.Overwrite,
true, FtpVerify.Retry);
var msg = status switch
{
FtpStatus.Success => "file successfully uploaded",
FtpStatus.Failed => "failed to upload file",
_ => "unknown"
};
Console.WriteLine(msg);
The program uploads a file and prints a message.
var status = con.UploadFile(lpath, rpath, FtpRemoteExists.Overwrite,
true, FtpVerify.Retry);
We upload a file to the FTP server with UploadFile. The remote file
is overwritten if it already exists. The fourth parameter tells the client to
create the remote directory if it does not exist. We retry the upload a few
times if it fails.
var msg = status switch
{
FtpStatus.Success => "file successfully uploaded",
FtpStatus.Failed => "failed to upload file",
_ => "unknown"
};
Depending on the returned status value, we print a message to the terminal.
$ dotnet run file successfully uploaded
C# FluentFTP list directory
The next example lists the contents of the given remote directory.
using FluentFTP;
var host = "example.com";
var username = "user7";
var passwd = "s$cret";
var path = "/";
using var con = new FtpClient(host, username, passwd);
con.Connect();
var items = con.GetListing(path);
foreach (FtpListItem item in items) {
if (item.Type == FtpObjectType.File) {
Console.WriteLine($"f {item.Name}");
} else if (item.Type == FtpObjectType.Directory) {
Console.WriteLine($"d {item.Name}");
} else {
Console.WriteLine($"{item.Name}");
}
}
The program lists the contents of the root directory. In the listing we specify whether the item is a file or a directory.
var items = con.GetListing(path);
The GetListing method returns a file listing from the server. Each
FtpListItem object returned contains information about the item.
foreach (FtpListItem item in items) {
if (item.Type == FtpObjectType.File) {
Console.WriteLine($"f {item.Name}");
} else if (item.Type == FtpObjectType.Directory) {
Console.WriteLine($"d {item.Name}");
} else {
Console.WriteLine($"{item.Name}");
}
}
We go over the array of the FTP list items and print each name to the console. We prepend an f character for files and d for directories.
$ dotnet run f readme.txt d web
C# FluentFTP async client
The AsyncFtpClient provides asynchronous versions of the methods.
In the next example, we recursively list all files in a directory.
using FluentFTP;
var host = "example.com";
var username = "user7";
var passwd = "s$cret";
await using var con = new AsyncFtpClient(host, username, passwd);
await con.Connect();
foreach (var item in await con.GetListing("/web", FtpListOption.Recursive))
{
if (item.Type == FtpObjectType.File)
{
Console.WriteLine($"{item.FullName} {item.Size} B {item.Modified:yyyy-MM-dd}");
}
}
await con.Disconnect();
The program prints the full path, the size, and the modification date of each
file in the /web directory and its subdirectories.
await using var con = new AsyncFtpClient(host, username, passwd); await con.Connect();
We create an asynchronous client and connect to the server. The
await using statement disposes the client asynchronously.
foreach (var item in await con.GetListing("/web", FtpListOption.Recursive))
With the FtpListOption.Recursive option, the listing includes the
contents of all subdirectories.
$ dotnet run /web/test/index.html 35 B 2026-10-15 /web/csharp/quest-pdf/index.html 35 B 2026-10-15
Source
In this article we have covered the FluentFTP library. We have shown how to create a directory, download and upload a file, and list directory contents.
Author
List all C# tutorials.