如何在 .NET 应用程序中从 FTP 协议获取目录文件大小

发布于 2024-12-11 13:46:37 字数 287 浏览 0 评论 0原文

我目前正在制作一个小型 .NET 控制台应用程序,用于将我的一些文件自动备份到我的服务器上。我遇到的问题是我这边遇到了一些恶劣的天气,导致一些电力和网络中断。在此期间,我注意到我的文件的很大一部分没有通过或已损坏。我想知道是否有办法获取另一端文件夹的大小,并查看文件名、文件数量和总目录大小是否匹配。我已经尝试过 WinSCP 和 NcFTP 作为传输文件的方法,但我还没有看到任何有关获得正确文件大小的信息。

这几乎是一个 Windows 到 Windows 的传输,因此如果有一个命令行参数可以通过 FTP 客户端返回一个大小,那就太好了。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

初熏 2024-12-18 13:46:37

没有标准的 FTP 命令来检索目录大小。

您必须递归迭代所有子目录和文件并对大小求和。

这对于 .NET Framework/FtpWebRequest 来说并不容易,因为它不支持 MLSD 命令,而该命令是在 FTP 协议中检索具有文件属性的目录列表的唯一可移植方法。

您所能做的就是使用LIST命令(ListDirectoryDe​​tails)并尝试解析特定于服务器的列表。许多 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.ListDirectoryDe​​tails FTP 响应


或者,您可以使用支持现代 MLSD 命令的第 3 方 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 的作者)

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)

呆° 2024-12-18 13:46:37

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

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.

不疑不惑不回忆 2024-12-18 13:46:37

我认为最好的办法是获取完整的文件列表,然后一次发送一个。如果传输期间连接失败,则文件上传将失败。如果文件上传成功,您可以从列表中删除该文件名。

正如您在标签中提到的那样,也许您应该此处查找如何在 C# 中执行它的示例。 VB.Net 会类似,但它会给你一个想法。

您可以获取此处所示的目录列表。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文