C# 从FTP下载文件的进度-TotalByTestOreReceive始终为-1?
我正在尝试从带有进度条的FTP服务器下载文件 文件正在下载,ProgressChanged事件正在调用,但args TotalBytesToReceive始终为-1的事件除外。TotalBytes会增加,但如果没有总数,我无法计算百分比 我想我可以通过其他ftp命令找到文件大小,但我想知道为什么这不起作用 我的代码:C# 从FTP下载文件的进度-TotalByTestOreReceive始终为-1?,c#,asynchronous,ftp,webclient,C#,Asynchronous,Ftp,Webclient,我正在尝试从带有进度条的FTP服务器下载文件 文件正在下载,ProgressChanged事件正在调用,但args TotalBytesToReceive始终为-1的事件除外。TotalBytes会增加,但如果没有总数,我无法计算百分比 我想我可以通过其他ftp命令找到文件大小,但我想知道为什么这不起作用 我的代码: FTPClient request = new FTPClient(); request.Credentials = credentials; request.DownloadPr
FTPClient request = new FTPClient();
request.Credentials = credentials;
request.DownloadProgressChanged += new DownloadProgressChangedEventHandler(request_DownloadProgressChanged);
//request.DownloadDataCompleted += new DownloadDataCompletedEventHandler(request_DownloadDataCompleted);
request.DownloadDataAsync(new Uri(folder + file));
while (request.IsBusy) ;
谢谢。FTP不会像HTTP那样为您提供内容大小,您自己做可能会更好
FtpWebRequest FTPWbReq = WebRequest.Create("somefile") as FtpWebRequest;
FTPWbReq .Method = WebRequestMethods.Ftp.GetFileSize;
FtpWebResponse FTPWebRes = FTPWbReq.GetResponse() as FtpWebResponse;
long length = FTPWebRes.ContentLength;
FTPWebRes.Close();
所以我也有同样的问题。我通过首先检索文件大小来绕过它
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("URL");
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.Credentials = networkCredential;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
bytes_total = response.ContentLength; //this is an int member variable stored for later
Console.WriteLine("Fetch Complete, ContentLength {0}", response.ContentLength);
response.Close();
webClient = new MyWebClient();
webClient.Credentials = networkCredential; ;
webClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(FTPDownloadCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(FTPDownloadProgressChanged);
webClient.DownloadDataAsync(new Uri("URL"));
然后在回调函数中进行计算
private void FTPDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar.Value = (int)(((float)e.BytesReceived / (float)bytes_total) * 100.0);
}
对于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)不这样做
如果您的服务器没有提供大小信息,您必须在下载之前自己查询大小。使用和的完整解决方案: 核心下载代码基于:
似乎您必须提供一个更好的
WebClient
实现来处理这个问题。查找要覆盖的有趣属性/方法。查看了WebClient
,但如果没有大量的黑客攻击,它几乎不可能实现。
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("URL");
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.Credentials = networkCredential;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
bytes_total = response.ContentLength; //this is an int member variable stored for later
Console.WriteLine("Fetch Complete, ContentLength {0}", response.ContentLength);
response.Close();
webClient = new MyWebClient();
webClient.Credentials = networkCredential; ;
webClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(FTPDownloadCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(FTPDownloadProgressChanged);
webClient.DownloadDataAsync(new Uri("URL"));
private void FTPDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar.Value = (int)(((float)e.BytesReceived / (float)bytes_total) * 100.0);
}
private void button1_Click(object sender, EventArgs e)
{
// Run Download on background thread
Task.Run(() => Download());
}
private void Download()
{
try
{
const string url = "ftp://ftp.example.com/remote/path/file.zip";
NetworkCredential credentials = new NetworkCredential("username", "password");
// Query size of the file to be downloaded
WebRequest sizeRequest = WebRequest.Create(url);
sizeRequest.Credentials = credentials;
sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
int size = (int)sizeRequest.GetResponse().ContentLength;
progressBar1.Invoke(
(MethodInvoker)(() => progressBar1.Maximum = size));
// Download the file
WebRequest request = WebRequest.Create(url);
request.Credentials = credentials;
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(@"C:\local\path\file.zip"))
{
byte[] buffer = new byte[10240];
int read;
while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, read);
int position = (int)fileStream.Position;
progressBar1.Invoke(
(MethodInvoker)(() => progressBar1.Value = position));
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}