C# e、 TotalByTestOreReceive返回值-1

C# e、 TotalByTestOreReceive返回值-1,c#,download,ftp,webclient,C#,Download,Ftp,Webclient,我有一个列表框,其中包含DirectAdmin用户备份的列表。使用WebRequestMethods.Ftp.ListDirectory填充列表,如下所示: 我可以使用右下角的按钮下载存档文件。当我点击按钮时,会出现另一个表单并下载归档文件 我的下载代码如下: public static void DownloadFile(string server, string username, ...) { Uri URI = new Uri($"ftp://{server}/{target

我有一个列表框,其中包含DirectAdmin用户备份的列表。使用
WebRequestMethods.Ftp.ListDirectory
填充列表,如下所示:

我可以使用右下角的按钮下载存档文件。当我点击按钮时,会出现另一个表单并下载归档文件

我的下载代码如下:

public static void DownloadFile(string server, string username, ...)
{
    Uri URI = new Uri($"ftp://{server}/{targetFilePath}");
    using (WebClient client = new WebClient())
    {
        client.Credentials = new NetworkCredential(username, password);
        if (progress != null)
        {
            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progress);
        }
        if (complete != null)
        {
            client.DownloadFileCompleted += new AsyncCompletedEventHandler(complete);
        }
        before?.Invoke();
        client.DownloadFileAsync(URI, localFilePath);
    }
}
这就是我传递给
DownloadFile()
方法的
DownloadProgressChanged
事件:

delegate (object s2, DownloadProgressChangedEventArgs e2)
{
    TransferLabel.Invoke((MethodInvoker)delegate
    {
       TransferLabel.Text = $"{(e2.BytesReceived / 1024).ToString()} KB / {(e2.TotalBytesToReceive / 1024).ToString()} KB";
    });
    TransferProgressBar.Invoke((MethodInvoker)delegate
    {
       TransferProgressBar.Value = (int)(e2.BytesReceived / (float)e2.TotalBytesToReceive * 100);
    });
}
我使用同样的方法上传文件,效果很好,但使用download
e2。TotalBytesToReceive
在整个过程中返回
-1

只有完成后,我才能得到正确的值:

为什么呢



我找到了解决这个问题的办法。我将把ListBox更改为ListView,并使用
ListDirectoryDetails
存储归档文件的大小。这样,我可以将
e.BytesReceived
与存储的总字节数进行比较,而不是
e.TotalBytesToReceive
。这将解决我的问题,但我仍然对这个问题感到好奇。为什么我会得到
-1
?我是做错了什么,还是这是一个与服务器相关的问题?还有,我可以做些什么来修复它(获得正确的值)?

当然,对于HTTP下载,在执行文件下载时,服务器可能不提供大小信息,并且在服务器发出完成的信号之前,您将无法获得任何有意义的信息

不确定是否使用FTP(我注意到FTP命令集中定义了一个单独的
SIZE
命令,因此在检索过程中包含这些信息可能被认为是多余的)


我有点惊讶,
TotalBytesToRetrieve
的文档没有更明确地说明信息不可用的可能性以及在这种情况下返回的内容。

对于FTP协议,
WebClient
通常不知道总下载大小。因此,您通常通过FTP获得
-1

另见

请注意,该行为实际上与.NET文档相矛盾,后者表示for(其中
TotalBytesToReceive
的值来自):

对于使用
DownloadFile
方法的请求,如果下载的文件包含数据,则属性大于零,如果文件为空,则属性为零

但是你会很容易地发现很多关于这方面的问题(就像我上面链接的问题),有效地表明这种行为并不总是如文档所示。
FtpWebResponse.ContentLength
仅对
GetFileSize
方法具有有意义的值


FtpWebRequest
/
WebClient
没有明确尝试找出它正在下载的文件的大小。它所做的只是尝试在
125
/
150
RETR
命令的响应中查找
(xxx字节)。
字符串。没有FTP RFC要求服务器包含此类信息。ProFTPD(请参阅)和vsftpd(请参阅
postlogin.c
中的
handle\u retr
)似乎包含此信息。其他常见的FTP服务器(IIS、FileZilla)不这样做。

阅读备注>此处的注意部分:“所以FTP总是得到-1”-这不是真的。我刚刚检查了一些公共ftp服务器,当使用
DownloadFile
时,它返回的ContentLength很好。我已经删除了它,但它是完全正常的。基本上就是
newwebclient()ftp://speedtest.tele2.net/500MB.zip)输出)
(与OP问题中的
DownloadProgressChanged
类似)。@Evk好的,我已经相应地更新了我的答案。