4

Вопрос по c#, windows-phone-8, async-await – Скачивание и сохранение файла Async в Windows Phone 8

Как я могу скачать и сохранить файл вIsolatedStorage асинхронно? я использовалWebClient сначала для цели, но я не мог дождаться завершения, поэтому я нашел некоторый полезный кодВот.

Тем не менее, это также не в полном формате. Я нашел функцию:

public static Task<Stream> DownloadFile(Uri url)
{
    var tcs = new TaskCompletionSource<Stream>();
    var wc = new WebClient();
    wc.OpenReadCompleted += (s, e) =>
    {
        if (e.Error != null) tcs.TrySetException(e.Error);
        else if (e.Cancelled) tcs.TrySetCanceled();
        else tcs.TrySetResult(e.Result);
    };
    wc.OpenReadAsync(url);
    return tcs.Task;
}

Но как я могу сохранить этот файл вIsolatedStorage? Кто-то, помогите мне завершить эту функцию!

На Windows Phone 8WebClient поддерживает асинхронное программирование на основе задач (см.TaskAsync суффиксированные методы). Тем не менееКласс HttpClient что вы можете получить его изКлиентские библиотеки Microsoft HTTP NuGet Пакет лучше подходит для асинхронного программирования. Ваш код станет намного чище.Task возвращающие асинхронные методы также должны иметь суффиксыасинхронный (исключение дляWebClient что уже былоасинхронный суффиксированные методы).

от Paulo Morgado
3 ответа
3

Это, что

har07 размещено, должно работать. В случае, если вам нужно немного расширить свой метод, я бы попробовал сделать что-то вроде этого (хотя это не проверено, но должно работать):

(Восстановлено после комментария - с отменой)

// first define Cancellation Token Source - I've made it global so that CancelButton has acces to it
CancellationTokenSource cts = new CancellationTokenSource();
enum Problem { Ok, Cancelled, Other }; // results of my Task

// cancelling button event
private void CancellButton_Click(object sender, RoutedEventArgs e)
{
   if (this.cts != null)
        this.cts.Cancel();
}

// the main method - I've described it a little below in the text
public async Task<Problem> DownloadFileFromWeb(Uri uriToDownload, string fileName, CancellationToken cToken)
{
   try
   {
       using (Stream mystr = await DownloadFile(uriToDownload))
           using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
           {
           if (ISF.FileExists(fileName)) return Problem.Other;
           using (IsolatedStorageFileStream file = ISF.CreateFile(fileName))
           {
               const int BUFFER_SIZE = 1024;
               byte[] buf = new byte[BUFFER_SIZE];

               int bytesread = 0;
               while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
               {
                  cToken.ThrowIfCancellationRequested();
                  file.Write(buf, 0, bytesread);
               }
           }
       }
       return Problem.Ok;
    }
    catch (Exception exc)
    {
       if (exc is OperationCanceledException)
           return Problem.Cancelled;
       else return Problem.Other; 
    }
}

// and download
private async void Downlaod_Click(object sender, RoutedEventArgs e)
{
   cts = new CancellationTokenSource();
   Problem fileDownloaded = await DownloadFileFromWeb(new Uri(@"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt", cts.Token);
   switch(fileDownloaded)
   {
      case Problem.Ok:
           MessageBox.Show("File downloaded");
           break;
      case Problem.Cancelled:
           MessageBox.Show("Download cancelled");
           break;
      case Problem.Other:
      default:
           MessageBox.Show("Other problem with download");
           break;
    }
}

Я добавил токен отмены - это означает, что ваша операция загрузки может быть отменена после Button.Click. С другой стороны, если await DownloadFile (uriToDownload) отменен, он автоматически выбрасывает OperationCancelled - тогда вы перехватываете это исключение и возвращаете адекватный результат.

Я не запускал этот код, но он может показать основную идею.

Как мы можем обработать отмену загрузки веб-клиента в этом случае. Я устанавливаю if (e.Cancelled) tcs.TrySetCanceled () ;. Но как я могу проверить это в главном потоке

от Jibin Mathew

@JMat Я отредактировал свой ответ и попытался добавить возможность отмены. Могут быть некоторые ошибки (я не управлял этим) - но, надеюсь, вы поняли основную идею.

от Romasz

Да, это сработало, и я борюсь со странной проблемой при загрузке файла. Исключение OutOf Memory. Если у вас есть предложения, пожалуйста, прокомментируйте сообщениеstackoverflow.com/questions/21594417/...

от Jibin Mathew
3

Попробуйте что-то вроде этого (не проверено):try

Попробуйте что-то вроде этого (не проверено):

try
{
    using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile("fileNameHere");

        BitmapImage bitmap = new BitmapImage();
        var stream = await DownloadFile(new Uri("http://someuri.com", UriKind.Absolute));
        bitmap.SetSource(stream);
        WriteableBitmap wb = new WriteableBitmap(bitmap);

        // Encode WriteableBitmap object to a JPEG stream.
        Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
        fileStream.Close();
    }
}
catch (Exception ex)
{
    //Exception handle appropriately for your app  
}

[Ссылка]

-1

На мой взгляд

лучший способ использовать нативную реализацию, подобную этой (Wrapping Begin / End asynchronous API):

var url = new Uri(UriString, UriKind.Absolute);
var fileName = Path.GetFileName(url.LocalPath);

var w = WebRequest.CreateHttp(url);
var response = await Task.Factory.FromAsync<WebResponse>(w.BeginGetResponse, w.EndGetResponse, null);
await response.GetResponseStream().CopyToAsync(new FileStream(ApplicationData.Current.LocalFolder.Path + @"\" + fileName, FileMode.CreateNew));

В этом вопросе дубликат того, который вы связали, пометьте его как дубликат, а не оставляйте ответ на этот вопрос. Если это не дубликат, оставьте полный ответ вместо ответа только по ссылке.

от josliber

Похожие вопросы