FtpWebRequest FTP скачать с ProgressBar
Мой код работает, но ProgressBar
сразу переместится на 100% и загрузка продолжится. Когда он закончится, приходит MessageBox для получения информации.
Я уже изменил размер буфера, но это не имеет значения.
Что я здесь не так делаю?
Вот мой код:
void workerDOWN_DoWork(object sender, DoWorkEventArgs e)
{
string fileFullPath = e.Argument as String;
string fileName = Path.GetFileName(fileFullPath);
string fileExtension = Path.GetExtension(fileName);
label4.Invoke((MethodInvoker)delegate { label4.Text = "Downloading File.."; });
string ftpServerIP = "XXX";
string ftpUserName = "XXX";
string ftpPassword = "XXX";
try
{
//Datei vom FTP Server downloaden
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
request.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(fileFullPath))
{
var buffer = new byte[32 * 1024];
int totalReadBytesCount = 0;
int readBytesCount;
while ((readBytesCount = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, readBytesCount);
totalReadBytesCount += readBytesCount;
var progress = (int)((float)totalReadBytesCount / (float)fileStream.Length * 100);
workerDOWN.ReportProgress((int)progress);
label3.Invoke((MethodInvoker)delegate { label3.Text = progress + " %"; });
}
}
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
MessageBox.Show("Datei nicht gefunden!", "Error");
}
}
e.Result = fileFullPath;
}
void workerDOWN_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string fileFullPath = e.Result as String;
string fileName = Path.GetFileName(fileFullPath);
MessageBox.Show("Download erfolgreich!","Information");
progressBar1.Value = 0;
label3.Invoke((MethodInvoker)delegate { label3.Text = " "; });
label4.Invoke((MethodInvoker)delegate { label4.Text = " "; });
}
3 ответа
Тривиальный пример загрузки через FTP FtpWebRequest
с индикатором выполнения WinForms:
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);
}
}
Код загрузки ядра основан на:
Загрузить и загрузить двоичный файл на / с FTP-сервера в C#/.NET
Чтобы объяснить, почему ваш код не работает:
- Вы используете размер целевого файла для расчета:
fileStream.Length
- это всегда будет равноtotalReadBytesCount
, следовательноprogress
всегда будет 100. - Вы, вероятно, хотели использовать
ftpStream.Length
, но это не может быть прочитано. - В основном с протоколом FTP, вы не знаете размер загружаемого файла. Если вам нужно это знать, вы должны явно запросить его перед загрузкой. Здесь я использую
WebRequestMethods.Ftp.GetFileSize
для этого.
Теперь у меня есть решение, которое работает для меня.
Идея получить первый размер файла была отличной. Но когда я впервые делаю запрос для проверки размера файла, Ftp-сервер выдает ошибку. Как эта ошибка FtpWebRequest: 550 Размер не допускается в режиме ASCII
Теперь сначала я загружаю фиктивный файл, чтобы открыть соединение. См. Ниже
Спасибо всем за поддержку.
Великое Сообщество. Благодарю.
void workerDOWN_DoWork(object sender, DoWorkEventArgs e)
{
string fileFullPath = e.Argument as String;
string fileName = Path.GetFileName(fileFullPath);
string fileExtension = Path.GetExtension(fileName);
label4.Invoke((MethodInvoker)delegate { label4.Text = "Downloading File.."; });
//FTP Download und Delete
string ftpServerIP = "XXX";
string ftpUserName = "XXXX";
string ftpPassword = "XXXXX";
try
{
// dummy download ftp connection for ftp server bug
FtpWebRequest DummyRequest = (FtpWebRequest)WebRequest.Create(("ftp://" + ftpServerIP + "/anyfile"));
DummyRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
DummyRequest.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = DummyRequest.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(Path.GetDirectoryName(Application.ExecutablePath) + "\\anyfile"))
{
ftpStream.CopyTo(fileStream);
}
//delete downloaded test file
File.Delete(Path.GetDirectoryName(Application.ExecutablePath) + "\\anyfile");
// Query size of the file to be downloaded
FtpWebRequest sizeRequest = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
sizeRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
var fileSize = sizeRequest.GetResponse().ContentLength;
//file download
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
request.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(fileFullPath))
{
var buffer = new byte[32 * 1024];
int totalReadBytesCount = 0;
int readBytesCount;
while ((readBytesCount = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, readBytesCount);
totalReadBytesCount += readBytesCount;
var progress = (int)((float)totalReadBytesCount / (float)fileSize * 100);
workerDOWN.ReportProgress((int)progress);
label3.Invoke((MethodInvoker)delegate { label3.Text = progress + " %"; });
}
}
// delete file on ftp server
FtpWebRequest Delrequest = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
Delrequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
Delrequest.Method = WebRequestMethods.Ftp.DeleteFile;
FtpWebResponse Delresponse = (FtpWebResponse)Delrequest.GetResponse();
Delresponse.Close();
// message file deleted
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("System: " + fileName + " wurde auf dem Server gelöscht." + Environment.NewLine); });
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
MessageBox.Show("Datei nicht gefunden!", "Error");
}
}
e.Result = fileFullPath;
}
void workerDOWN_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
void workerDOWN_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string fileFullPath = e.Result as String;
string fileName = Path.GetFileName(fileFullPath);
MessageBox.Show("Download erfolgreich!","Information");
progressBar1.Value = 0;
label3.Invoke((MethodInvoker)delegate { label3.Text = " "; });
label4.Invoke((MethodInvoker)delegate { label4.Text = " "; });
}
Не зная точно, что ваш код в ProgressChanged
Eventhandler делает, я думаю, что вы непреднамеренно поставили скобки в свой расчет прогресса после * 100
,
Вы можете попробовать это:
var progress = (int)((float)totalReadBytesCount / (float)fileStream.Length) * 100;