Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
430 views
in Technique[技术] by (71.8m points)

windows phone 8: how to download xml file from web and save it to local?

I would like to download a xml file from web, then save it to the local storage but I do not know how to do that. Please to help me clearly or give me an example. Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Downloading a file is a huge subject and can be done in many ways. I assume that you know the Uri of the file you want to download, and want you mean by local is IsolatedStorage.

I'll show three examples how it can be done (there are also other ways).

1. The simpliest example will dowload string via WebClient:

public static void DownloadFileVerySimle(Uri fileAdress, string fileName)
{
   WebClient client = new WebClient();
   client.DownloadStringCompleted += (s, ev) =>
   {
       using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
       using (StreamWriter writeToFile = new StreamWriter(ISF.CreateFile(fileName)))
           writeToFile.Write(ev.Result);
   };
   client.DownloadStringAsync(fileAdress);
}

As you can see I'm directly downloading string (ev.Result is a string - that is a disadventage of this method) to IsolatedStorage. And usage - for example after Button click:

private void Download_Click(object sender, RoutedEventArgs e)
{
   DownloadFileVerySimle(new Uri(@"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt");
}

2. In the second method (simple but more complicated) I'll use again WebClient and I'll need to do it asynchronously (if you are new to this I would suggest to read MSDN, async-await on Stephen Cleary blog and maybe some tutorials).

First I need Task which will download a Stream from web:

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

Then I'll write my method downloading a file - it also need to be async as I'll use await DownloadStream:

public enum DownloadStatus { Ok, Error };

public static async Task<DownloadStatus> DownloadFileSimle(Uri fileAdress, string fileName)
{
   try
   {
       using (Stream resopnse = await DownloadStream(new Uri(@"http://filedress/myfile.txt", UriKind.Absolute)))
         using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
         {
            if (ISF.FileExists(fileName)) return DownloadStatus.Error;
            using (IsolatedStorageFileStream file = ISF.CreateFile(fileName))
                resopnse.CopyTo(file, 1024);
            return DownloadStatus.Ok;
         }
   }
   catch { return DownloadStatus.Error; }
}

And usage of my method for example after Button click:

private async void Downlaod_Click(object sender, RoutedEventArgs e)
{
   DownloadStatus fileDownloaded = await DownloadFileSimle(new Uri(@"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt");
   switch (fileDownloaded)
   {
       case DownloadStatus.Ok:
            MessageBox.Show("File downloaded!");
            break;
       case DownloadStatus.Error:
       default:
            MessageBox.Show("There was an error while downloading.");
            break;
    }
}

This method can have problems for example if you try to download very big file (example 150 Mb).

3. The third method - uses WebRequest with again async-await, but this method can be changed to download files via buffer, and therefore not to use too much memory:

First I'll need to extend my Webrequest by a method that will asynchronously return a Stream:

public static class Extensions
{
    public static Task<Stream> GetRequestStreamAsync(this WebRequest webRequest)
    {
        TaskCompletionSource<Stream> taskComplete = new TaskCompletionSource<Stream>();
        webRequest.BeginGetRequestStream(arg =>
        {
            try
            {
                Stream requestStream = webRequest.EndGetRequestStream(arg);
                taskComplete.TrySetResult(requestStream);
            }
            catch (Exception ex) { taskComplete.SetException(ex); }
        }, webRequest);
        return taskComplete.Task;
    }
}

Then I can get to work and write my Downloading method:

public static async Task<DownloadStatus> DownloadFile(Uri fileAdress, string fileName)
{
   try
   {
      WebRequest request = WebRequest.Create(fileAdress);
      if (request != null)
      {
          using (Stream resopnse = await request.GetRequestStreamAsync())
          {
             using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
             {
                  if (ISF.FileExists(fileName)) return DownloadStatus.Error;
                    using (IsolatedStorageFileStream file = ISF.CreateFile(fileName))
                    {
                       const int BUFFER_SIZE = 10 * 1024;
                       byte[] buf = new byte[BUFFER_SIZE];

                       int bytesread = 0;
                       while ((bytesread = await resopnse.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
                                file.Write(buf, 0, bytesread);
                   }
             }
             return DownloadStatus.Ok;
         }
     }
     return DownloadStatus.Error;
  }
  catch { return DownloadStatus.Error; }
}

Again usage:

private async void Downlaod_Click(object sender, RoutedEventArgs e)
{
   DownloadStatus fileDownloaded = await DownloadFile(new Uri(@"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt");
   switch (fileDownloaded)
   {
       case DownloadStatus.Ok:
           MessageBox.Show("File downloaded!");
           break;
       case DownloadStatus.Error:
       default:
           MessageBox.Show("There was an error while downloading.");
           break;
   }
}

Those methods of course can be improved but I think this can give you an overview how it can look like. The main disadvantage of these methods may be that they work in foreground, which means that when you exit your App or hit start button, downloading stops. If you need to download in background you can use Background File Transfers - but that is other story.

As you can see you can reach your goal in many ways. You can read more about those methods on many pages, tutorials and blogs, compare an choose the most suitable.

Hope this helps. Happy coding and good luck.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...