Могу ли я создать индикатор выполнения загрузки внутри блока итератора? - PullRequest
0 голосов
/ 01 марта 2012

Я знаю, что индикаторы прогресса уже были заданы до смерти, но у меня проблемы с одним. Мне нужно скачать файл через FTP, я использую WebClient, загруженные данные должны быть сохранены в байтовом массиве, но WebClient.DownloadDataAsync не может вернуть его напрямую, поэтому я должен использовать метод DownloadDataCompleted для доступа к данным , Все до тех пор, пока все в порядке, но проблема в том, что я не могу «приостановить» блок IEnumerator, не блокируя весь поток, и если я не приостановлю его, приложение вылетает, потому что байтовый массив не существует, когда он пытается получить к нему доступ. Когда файл для скачивания находился в формате http, я использовал WWW, и у меня не было проблем, но его пришлось перенести на FTP. Использование WebClient.DownloadData работает, но меня попросили включить индикатор выполнения. В любом случае, вот код:

    IEnumerator DownloadGame(Dictionary<string, string> settingsDict)
    {
       statusText = "Starting download...";
       WebClient request = new WebClient();
       request.Credentials = new NetworkCredential("user", "password");
       request.DownloadDataCompleted += DownloadDataCompleted;

      //byte[] fileData = request.DownloadData(settingsDict["downloadlink"]); This works, but is no good since it blocks the thread
    request.DownloadDataAsync(new Uri(settingsDict["downloadlink"]),"somefilepath");


    //do{}while(!downloadFinished); This also works but blocks the thread anyway


    //Process the update
    string tmpRoot = TMPFolder();
    string tmpFolder = tmpRoot + Application.platform + settingsDict["latestVersion"] + "/";
    if (!UnzipUpdate(fileData, tmpFolder))//fail here, in this case fileData is global
    {
        DeleteDirectory(tmpRoot); 
        yield break;
    }
    if (!ProcessUpdateData(tmpFolder))
    {
        DeleteDirectory(tmpRoot); 
        yield break;
    }
    DeleteDirectory(tmpRoot);

    settingsDict["thisVersion"] = GetNextVersion();
}

 void DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e){

   fileData = e.Result;
   downloadFinished = true;
 }

1 Ответ

0 голосов
/ 01 марта 2012

вы можете использовать что-то подобное, основываясь на предыдущем посте Stakoverflow.

Самое простое - использовать BackgroundWorker и поместить свой код в обработчик событий DoWork.И сообщать о прогрессе с помощью BackgroundWorker.ReportProgress.

Основная идея:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var ftpWebRequest = (FtpWebRequest)WebRequest.Create("ftp://xxx.com");
    ftpWebRequest.Method = WebRequestMethods.Ftp.UploadFile; //or DownLoad
    using (var inputStream = File.OpenRead(fileName))
    using (var outputStream = ftpWebRequest.GetRequestStream())
    {
        var buffer = new byte[1024 * 1024];
        int totalReadBytesCount = 0;
        int readBytesCount;
        while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            outputStream.Write(buffer, 0, readBytesCount);
            totalReadBytesCount += readBytesCount;
            var progress = totalReadBytesCount * 100.0 / inputStream.Length;
            backgroundWorker1.ReportProgress((int)progress);
        }
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar.Value = e.ProgressPercentage;
}

Убедитесь, что WorkerReportsProgress включен

backgroundWorker2.WorkerReportsProgress = true;

С BackgroundWorker вы также можетелегко осуществить отмену загрузки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...