C# 在Windows Phone 8中异步下载和保存文件

C# 在Windows Phone 8中异步下载和保存文件,c#,windows-phone-8,async-await,C#,Windows Phone 8,Async Await,如何异步下载文件并将其保存到IsolatedStorage? 我首先使用了WebClient,但是我不能等到完成,所以我找到了一些有用的代码 然而,这也不是完整的格式。我发现这个函数: public static Task<Stream> DownloadFile(Uri url) { var tcs = new TaskCompletionSource<Stream>(); var wc = new WebClient(); wc.OpenRea

如何异步下载文件并将其保存到
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;
}
公共静态任务下载文件(Uri url)
{
var tcs=new TaskCompletionSource();
var wc=新的WebClient();
wc.OpenReadCompleted+=(s,e)=>
{
如果(e.Error!=null)tcs.TrySetException(e.Error);
否则,如果(如取消)tcs.TrySetCanceled();
其他tcs.TrySetResult(e.Result);
};
OpenReadAsync(url);
返回tcs.Task;
}
但是如何将此文件保存到
隔离存储
?有人帮我完成这个功能

试试这样的方法(未经测试):

[]

这篇文章应该有用。如果您需要稍微扩展您的方法,我会尝试这样做(虽然它没有经过测试,但应该可以工作):

(注释后重建-取消)

//首先定义取消令牌源-我将其设置为全局,以便CancelButton可以访问它
CancellationTokenSource cts=新的CancellationTokenSource();
枚举问题{确定,已取消,其他};//我的任务结果
//取消按钮事件
私有作废取消按钮\单击(对象发送者,路由目标e)
{
如果(this.cts!=null)
this.cts.Cancel();
}
//主要方法-我已经在下面的文本中对其进行了描述
公共异步任务从Web下载文件(Uri uriToDownload,字符串文件名,CancellationToken)
{
尝试
{
使用(Stream mystr=wait DownloadFile(uriToDownload))
使用(IsolatedStorageFile ISF=IsolatedStorageFile.GetUserStoreForApplication())
{
如果(ISF.FileExists(fileName))返回问题;
使用(IsolatedStorageFileStream文件=ISF.CreateFile(文件名))
{
const int BUFFER_SIZE=1024;
字节[]buf=新字节[缓冲区大小];
int字节读取=0;
而((bytesread=await mystr.ReadAsync(buf,0,BUFFER_SIZE))>0)
{
cToken.ThrowIfCancellationRequested();
file.Write(buf,0,bytesread);
}
}
}
返回问题。好的;
}
捕获(异常exc)
{
如果(exc为操作取消异常)
退货问题。取消;
否则返回问题。其他;
}
}
//下载
private async void Downlaud_Click(对象发送方、路由目标方)
{
cts=新的CancellationTokenSource();
Problem fileDownloaded=等待下载FileFromWeb(新Uri)(@)http://filedress/myfile.txt,UriKind.Absolute),“myfile.txt”,cts.Token);
交换机(文件下载)
{
案例问题。好的:
MessageBox.Show(“下载的文件”);
打破
案例问题。已取消:
MessageBox.Show(“下载已取消”);
打破
案例问题。其他:
违约:
显示(“其他下载问题”);
打破
}
}
我添加了取消令牌-这意味着您的下载操作可以在单击按钮后取消。单击。另一方面,如果Wait DownloadFile(uriToDownload)被取消,它将自动抛出OperationCancelled-然后您将捕获该异常并返回适当的结果。


我还没有运行该代码,但它可能显示了主要思想。

在我看来,像这样使用本机实现的最佳方式(包装Begin/End asynchronous API):

var url=newuri(UriString,UriKind.Absolute);
var fileName=Path.GetFileName(url.LocalPath);
var w=WebRequest.CreateHttp(url);
var response=await Task.Factory.fromsync(w.BeginGetResponse,w.EndGetResponse,null);
等待响应.GetResponseStream().CopyToAsync(新文件流(ApplicationData.Current.LocalFolder.Path+@“\”+文件名,FileMode.CreateNew));

在这种情况下,我们如何处理取消webclient下载。我设置了if(e.Cancelled)tcs.trysetconceled();。但是我怎样才能在主屏幕上查看呢thread@JMat我已经编辑了我的答案,并尝试添加取消功能。可能会有一些错误(我没有运行它)-但希望您能理解主要思想。是的,它工作正常,我在下载文件时遇到了一个奇怪的问题,内存不足异常。如果您有一些建议,请发表在Windows Phone 8上。
WebClient
支持基于任务的异步编程(请参阅TaskAsync后缀方法)。但是,您可以从NuGet软件包中获得的方法更适合异步编程。您的代码将变得更干净。
Task
返回的异步方法也应为后缀Async(已经有异步后缀方法的
WebClient
的例外)。如果此问题与您链接的问题重复,请将其标记为重复问题,而不是留下这样的答案。如果不是重复问题,请留下完整的答案,而不是仅链接的答案。
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  
}
// 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;
    }
}
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));