如何在.NET应用中通过FTP协议获取目录文件大小

3
我正在创建一个小的.NET控制台应用程序,用于将我的一些文件自动备份到服务器上。但是我遇到的问题是,我这边遭遇了一些恶劣的天气,导致停电和网络中断。在此期间,我注意到有很多文件没有传输成功或损坏了。我想知道是否有一种方法来获取另一端文件夹的大小,并查看文件名、文件数量和总目录大小是否匹配。我尝试使用WinSCP和NcFTP来传输文件,但我没有找到任何关于获取正确文件大小的信息。
基本上这是从 Windows 到 Windows 的传输,因此,如果有一个通过 FTP 客户端返回大小的命令行参数,那就太好了。

1
你为什么选择FTP?你愿意尝试其他协议吗? - CodesInChaos
根据其他协议的情况,我可以试一下。目前只有使用FTP因为速度较快。 - Seb
3个回答

2

没有标准的FTP命令来获取目录大小。

您需要递归迭代所有子目录和文件并计算其大小。

使用.NET框架/FtpWebRequest并不容易,因为它不支持MLSD命令,这是在FTP协议中检索带有文件属性的目录列表的唯一可移植方式。

您只能使用LIST命令(ListDirectoryDetails),并尝试解析特定于服务器的列表。许多FTP服务器使用*nix风格的列表,但许多服务器使用不同的格式。以下示例使用*nix格式:

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;
}

使用方法如下:

var credentials = new NetworkCredential("username", "password");
long size = CalculateFtpDirectorySize("ftp://ftp.example.com/", credentials);

如果您的服务器使用DOS/Windows列表格式,请参见C#类来解析WebRequestMethods.Ftp.ListDirectoryDetails FTP响应


或者,您可以使用支持现代MLSD命令的第三方FTP客户端实现。

例如WinSCP .NET程序集支持这一点。

它甚至有一个方便的Session.EnumerateRemoteFiles方法,使计算目录大小成为一项简单的任务:

var opts = EnumerationOptions.AllDirectories;
var files = session.EnumerateRemoteFiles("/", null, opts);
long size = files.Select(fileInfo => fileInfo.Length).Sum();

完整的代码应该像这样:
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();
}

(我是WinSCP的作者)


1

没有标准的方法来请求“此目录中文件的总大小”。您可以通过SIZE file.txt逐个请求每个文件的大小,或者您可以请求整个目录的ls -l并解析文件大小。


这种方法对于包含大文件的目录并尝试通过网络解析它来说很繁琐,但总体而言似乎是有效的。感谢您的帮助。 - Seb

0

我认为你最好的选择是获取完整的文件列表,然后逐个发送。如果传输过程中连接失败,则该文件上传将失败。如果文件上传成功,则可以从列表中删除该文件名。

正如你在标签中提到的NET,也许你应该看一下这里,了解如何在C#中执行它的示例。VB.Net会类似,但它会给你一个想法。

你可以像这里所示那样获取目录列表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接