How to get a directories file size from an FTP protocol in a .NET application

喜欢而已 提交于 2021-02-04 06:16:35

问题


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.


回答1:


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.




回答2:


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 (FtpWebResponse 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 files = session.EnumerateRemoteFiles("/", null, EnumerationOptions.AllDirectories);
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 files = session.EnumerateRemoteFiles("/", null, EnumerationOptions.AllDirectories);
    long size = files.Select(fileInfo => fileInfo.Length).Sum();
}

(I'm the author of WinSCP)




回答3:


I think that your best bet is to obtain a full list of files and then send them one at a time. If the connection fails during transfer then that file upload will fail. If a file upload is successful then you can remove that file name from the list.

as you've mentioned NET in your tags perhaps you should look here for an example of how to perform it in C#. VB.Net will be similar, but it will give you an idea.

You can get a directory list as shown here.



来源:https://stackoverflow.com/questions/7891677/how-to-get-a-directories-file-size-from-an-ftp-protocol-in-a-net-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!