【问题标题】:windows phone 8: how to download xml file from web and save it to local?windows phone 8:如何从 web 下载 xml 文件并将其保存到本地?
【发布时间】:2014-02-18 16:48:50
【问题描述】:

我想从网上下载一个 xml 文件,然后将其保存到本地存储,但我不知道该怎么做。请清楚地帮助我或给我一个例子。谢谢。

【问题讨论】:

    标签: windows-phone-8


    【解决方案1】:

    下载文件是一个庞大的主题,可以通过多种方式完成。我假设您知道要下载的文件的 Uri,并且希望您的意思是 localIsolatedStorage

    我将展示三个示例(还有其他方法)。

    1.最简单的例子将通过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);
    }
    

    如您所见,我正在将字符串(ev.Resultstring - 这是此方法的缺点)直接下载到 IsolatedStorage。 和用法 - 例如在按钮点击后:

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

    2。在第二种方法中(简单但更复杂)我将再次使用WebClient,我需要异步执行(如果您不熟悉此方法,我建议阅读MSDNasync-await on Stephen Cleary blog也许还有一些tutorials)。

    首先我需要Task,它将从网络下载Stream

    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;
    }
    

    然后我将编写下载文件的方法 - 它也需要异步,因为我将使用 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; }
    }
    

    以及我的方法的用法,例如在按钮单击后:

    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;
        }
    }
    

    如果您尝试下载非常大的文件(例如 150 Mb),此方法可能会出现问题。

    3.第三种方法 - 再次使用WebRequest 和async-await,但是可以将此方法更改为通过缓冲区下载文件,因此不会占用太多内存:

    首先我需要通过一个异步返回Stream的方法来扩展我的Webrequest

    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;
        }
    }
    

    然后我可以开始工作并编写我的下载方法:

    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; }
    }
    

    再次使用:

    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;
       }
    }
    

    这些方法当然可以改进,但我认为这可以让您大致了解它的外观。这些方法的主要缺点可能是它们在前台工作,这意味着当您退出应用程序或点击开始按钮时,下载停止。如果您需要在后台下载,您可以使用Background File Transfers - 但这是另一回事。

    如您所见,您可以通过多种方式实现目标。您可以在许多页面、教程和博客上阅读有关这些方法的更多信息,比较并选择最合适的。

    希望这会有所帮助。编码愉快,祝你好运。

    【讨论】:

    • 谢谢罗马兹。保存此文件后,您能告诉我计算机中的 IsolatedStorage 文件夹在哪里吗?
    • @Carson IsolatedStorage 文件夹在您的手机中,这是与您的应用程序严格连接的“地方”,没有其他应用程序可以访问它。但是,您当然可以通过IsolatedStorage ExplorerIsolatedStorage Spy 探索您的开发者设备(或模拟器)。
    • @Carson 欢迎您。另请参阅我提到的(在下一次编辑之后)关于后台下载 - 它有时可能很有用。快乐编码
    • @Carson 然后你发现了下载字符串的下一个缺点;) - 事实上字符串可以有不同的编码。要解决您的问题,您可能只需要更改 streamwriter 的编码,下面的行应该修复您的文件大小: using (StreamWriter writeToFile = new StreamWriter(ISF.CreateFile(fileName), Encoding.Unicode))
    • 我要感谢你千百次。我的每一个问题都解决了。
    猜你喜欢
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多