我正在尝试从带有进度条的FTP服务器下载文件。
文件正在下载,并且ProgressChanged事件正在调用,除非事件args TotalBytesToReceive始终为-1。 TotalBytes增加,但我无法计算没有总数的百分比。
我想我可以通过其他ftp命令找到文件大小,但我想知道为什么这不起作用?
我的代码:
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) ;
...
static void request_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
if (e.TotalBytesToReceive == -1)
{
l.reportProgress(-1, FormatBytes(e.BytesReceived) + " out of ?" );
}
else
{
l.reportProgress(e.ProgressPercentage, "Downloaded " + FormatBytes(e.BytesReceived) + " out of " + FormatBytes(e.TotalBytesToReceive) + " (" + e.ProgressPercentage + "%)");
}
}
...
class FTPClient : WebClient
{
protected override WebRequest GetWebRequest(System.Uri address)
{
FtpWebRequest req = (FtpWebRequest)base.GetWebRequest(address);
req.UsePassive = false;
return req;
}
}
感谢。
答案 0 :(得分:4)
所以我遇到了同样的问题。我首先通过检索文件大小来解决它。
// 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);
}
答案 1 :(得分:2)
使用FTP协议,WebClient
通常不知道总下载大小。所以你通常使用FTP获得-1
。
请注意,该行为实际上与.NET文档相矛盾,后者表示FtpWebResponse.ContentLength
(TotalBytesToReceive
的值来自):
对于使用
DownloadFile
方法的请求,如果下载的文件包含数据,则属性大于零;如果为空,则属性为零。
但是你很容易找到很多关于这方面的问题,有效地表明这种行为并不总是记录在案。 FtpWebResponse.ContentLength
仅对GetFileSize
方法具有有意义的值。
FtpWebRequest
/ WebClient
没有明确尝试找出正在下载的文件的大小。它所做的只是它试图在(xxx bytes).
/ 125
对150
命令的响应中查找RETR
字符串。没有FTP RFC要求服务器应包含此类信息。 ProFTPD(请参阅data_pasv_open
in src/data.c
)和vsftpd(请参阅handle_retr
中的postlogin.c
)似乎包含此信息。其他常见的FTP服务器(IIS,FileZilla)不这样做。
如果您的服务器未提供大小信息,则必须在下载之前自行查询大小。使用FtpWebRequest
和Task
的完整解决方案:
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);
}
}
核心下载代码基于:
Upload and download a binary file to/from FTP server in C#/.NET
答案 2 :(得分:-1)
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();