I am currently making a small .NET console application to do an automateed backup of some of my files onto my server. The issue that I am running into is that I've had some bad weather on my end which led to some power and network outages. During this time I noticed that a good portion of my files didn't go through or got corrupt. I was wondering if there was a way to get a size of the folder on the other end and see if the file names, number of files, and total directory size match up. I've tried WinSCP and NcFTP as ways to transfer files over, but I haven't seen anything regarding getting a proper filesize.
This is pretty much a windows to windows transfer so if there is a command line argument that gives me back a size through the FTP client that would be great.
There's no standard FTP command to retrieve a directory size.
You have to recursively iterate all subdirectories and files and sum the sizes.
This is not easy with .NET framework/FtpWebRequest, as it does not support the MLSD command, which is the only portable way to retrieve directory listing with file attributes in FTP protocol.
All you can do is to use LIST command (ListDirectoryDetails) and try to parse a server-specific listing. Many FTP servers use *nix-style listing. But many servers use a different format. The following example uses *nix format:
static long CalculateFtpDirectorySize(string url, NetworkCredential credentials)
{
FtpWebRequest listRequest = (FtpWebRequest)WebRequest.Create(url);
listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
listRequest.Credentials = credentials;
List<string> lines = new List<string>();
using (var listResponse = (FtpWebResponse)listRequest.GetResponse())
using (Stream listStream = listResponse.GetResponseStream())
using (StreamReader listReader = new StreamReader(listStream))
{
while (!listReader.EndOfStream)
{
lines.Add(listReader.ReadLine());
}
}
long result = 0;
foreach (string line in lines)
{
string[] tokens =
line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries);
string name = tokens[8];
string permissions = tokens[0];
string fileUrl = url + name;
if (permissions[0] == 'd')
{
result += CalculateFtpDirectorySize(fileUrl + "/", credentials);
}
else
{
result += long.Parse(tokens[4]);
}
}
return result;
}
Use it like:
var credentials = new NetworkCredential("username", "password");
long size = CalculateFtpDirectorySize("ftp://ftp.example.com/", credentials);
If your server uses DOS/Windows listing format, see C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
Alternatively you can use a 3rd party FTP client implementation that supports the modern MLSD command.
For example WinSCP .NET assembly supports that.
And it even has handy Session.EnumerateRemoteFiles method, which makes calculating directory size easy task:
var opts = EnumerationOptions.AllDirectories;
var files = session.EnumerateRemoteFiles("/", null, opts);
long size = files.Select(fileInfo => fileInfo.Length).Sum();
A complete code would be like:
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "ftp.example.com",
UserName = "username",
Password = "password",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
var opts = EnumerationOptions.AllDirectories;
var files = session.EnumerateRemoteFiles("/", null, opts);
long size = files.Select(fileInfo => fileInfo.Length).Sum();
}
(I'm the author of WinSCP)
There is no standard way to request "total size of files in this directory". You can ask for each file size individually via SIZE file.txt, or you can ask for ls -l of an entire directory and parse the file sizes out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With