跨平台文件I / O的第一个镜头
在一般情况下,您将使用DependencyService为您的Xamarin.Forms应用程序提供对文件I / O功能的访问。从之前对DependencyService的探索中可以了解到,您可以在Portable Class Library项目中的接口中定义所需的函数,而实现这些函数的代码则驻留在各个平台的不同类中。
本章开发的文件I / O函数将在第24章“页面导航”中的NoteTaker应用程序中得到很好的使用。对于文件I / O的第一个镜头,让我们使用一个更简单的解决方案,名为TextFileTryout ,它实现了几个用于处理文本文件的函数。让我们限制自己让这个程序在iOS和Android上运行,暂时忘记Windows平台。
使用DependencyService的第一步是在PCL中创建一个界面,定义您需要的所有方法。这是TextFileTryout项目中的这样一个名为IFileHelper的接口:

namespace TextFileTryout
{public interface IFileHelper{bool Exists(string filename);void WriteText(string filename, string text);string ReadText(string filename);IEnumerable<string> GetFiles();void Delete(string filename);}
}

该接口定义了用于确定文件是否存在,一次写入和读取整个文本文件,枚举应用程序创建的所有文件以及删除文件的函数。 在每个平台实现中,这些功能仅限于与应用程序关联的专用文件区域。
然后,您可以在每个平台中实现此接口。 这是iOS项目中的FileHelper类,包含using指令和所需的Dependency属性:

using System;
using System.Collections.Generic;
using System.IO;
using Xamarin.Forms;
[assembly: Dependency(typeof(TextFileTryout.iOS.FileHelper))]
namespace TextFileTryout.iOS
{class FileHelper : IFileHelper{public bool Exists(string filename){string filepath = GetFilePath(filename);return File.Exists(filepath);}public void WriteText(string filename, string text){string filepath = GetFilePath(filename);File.WriteAllText(filepath, text);}public string ReadText(string filename){string filepath = GetFilePath(filename);return File.ReadAllText(filepath);}public IEnumerable<string> GetFiles(){return Directory.GetFiles(GetDocsPath());}public void Delete(string filename){File.Delete(GetFilePath(filename));}// Private methods.string GetFilePath(string filename){return Path.Combine(GetDocsPath(), filename);}string GetDocsPath(){return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);}}
}

此类必须显式实现IFileHelper接口,并包含具有类名称的Dependency属性。这些允许Xamarin.Forms中的DependencyService类在平台项目中找到IFileHelper的这种实现。底部的两个私有方法允许程序使用Environment.GetFolderPath方法中可用的应用程序私有存储的目录来构造完全限定的文件名。
在Xamarin.iOS和Xamarin.Android中,Environment.GetFolderPath的实现获取应用程序本地存储的特定于平台的区域,尽管该方法为两个平台返回的目录名称非常不同。
因此,除了不同的命名空间名称之外,Android项目中的FileHelper类与iOS项目中的类完全相同。
iOS和Android版本的FileHelper使用File类中的静态快捷方法和Directory的简单静态方法来获取与应用程序一起存储的所有文件。但是,Windows 8.1和Windows Phone 8.1项目中的IFileHelper的实现无法使用File类中的快捷方法,因为它们不可用,并且UWP项目中的Environment.GetFolderPath方法不可用。
此外,为这些Windows平台编写的应用程序应该使用Windows运行时API中实现的文件I / O函数。由于Windows运行时中的文件I / O功能是异步的,因此它们不适合由IFileHelper接口建立的接口。出于这个原因,三个Windows项目中的FileHelper版本被迫离开关键方法未实现。这是UWP项目中的版本:

using System;
using System.Collections.Generic;
using Xamarin.Forms;
[assembly: Dependency(typeof(TextFileTryout.UWP.FileHelper))]
namespace TextFileTryout.UWP
{class FileHelper : IFileHelper{public bool Exists(string filename){return false;}public void WriteText(string filename, string text){throw new NotImplementedException("Writing files is not implemented");}public string ReadText(string filename){throw new NotImplementedException("Reading files is not implemented");}public IEnumerable<string> GetFiles(){return new string[0];}public void Delete(string filename){}}
}

除命名空间名称外,Windows 8.1和Windows Phone 8.1项目中的FileHelper版本相同。
通常,应用程序需要使用DependencyService.Get方法引用每个平台中的方法。 但是,TextFileTryout程序通过在PCL项目中定义一个名为FileHelper的类(也实现了IFileHelper)使事情变得容易,但是对DependencyService的Get方法的调用合并了这些方法的平台版本:

namespace TextFileTryout
{class FileHelper : IFileHelper{IFileHelper fileHelper = DependencyService.Get<IFileHelper>();public bool Exists(string filename){return fileHelper.Exists(filename);}public void WriteText(string filename, string text){fileHelper.WriteText(filename, text);}public string ReadText(string filename){return fileHelper.ReadText(filename);}public IEnumerable<string> GetFiles(){IEnumerable<string> filepaths = fileHelper.GetFiles();List<string> filenames = new List<string>();foreach (string filepath in filepaths){filenames.Add(Path.GetFileName(filepath));}return filenames;}public void Delete(string filename){fileHelper.Delete(filename);}}
}

请注意,GetFiles方法对从平台实现返回的文件名执行一些小手术。 从GetFiles的平台实现获得的文件名是完全限定的,虽然看到iOS和Android用于应用程序本地存储的文件夹名称可能很有趣,但这些文件名将显示在ListView中,其中文件夹名称 只会是一个分心,所以这个GetFiles方法剥离文件路径。
TextFileTryoutPage类测试这些函数。 XAML文件包括文件名条目,文件内容编辑器,标有“保存”的按钮,以及包含所有以前保存的文件名的ListView:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="TextFileTryout.TextFileTryoutPage"><ContentPage.Padding><OnPlatform x:TypeArguments="Thickness"iOS="0, 20, 0, 0" /></ContentPage.Padding><Grid><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="*" /><RowDefinition Height="Auto" /><RowDefinition Height="*" /></Grid.RowDefinitions><Entry x:Name="filenameEntry"Grid.Row="0"Placeholder="filename" /><Editor x:Name="fileEditor"Grid.Row="1"><Editor.BackgroundColor><OnPlatform x:TypeArguments="Color"WinPhone="#D0D0D0" /></Editor.BackgroundColor></Editor><Button x:Name="saveButton"Text="Save"Grid.Row="2"HorizontalOptions="Center"Clicked="OnSaveButtonClicked" /><ListView x:Name="fileListView"Grid.Row="3"ItemSelected="OnFileListViewItemSelected"><ListView.ItemTemplate><DataTemplate><TextCell Text="{Binding}"><TextCell.ContextActions><MenuItem Text="Delete"IsDestructive="True"Clicked="OnDeleteMenuItemClicked" /></TextCell.ContextActions></TextCell></DataTemplate></ListView.ItemTemplate> </ListView></Grid>
</ContentPage>

为了简单起见,所有处理都在没有ViewModel的代码隐藏文件中执行。 代码隐藏文件实现了XAML文件中的所有事件处理程序。 “保存”按钮检查文件是否首先存在,如果存在则显示警告框。 选择ListView中的一个文件将其加载。此外,ListView实现了一个上下文菜单来删除文件。 所有文件I / O函数都是PCL中定义的FileHelper类的方法,并实例化为类顶部的字段:

public partial class TextFileTryoutPage : ContentPage
{FileHelper fileHelper = new FileHelper();public TextFileTryoutPage(){InitializeComponent();RefreshListView();}async void OnSaveButtonClicked(object sender, EventArgs args){string filename = filenameEntry.Text;if (fileHelper.Exists(filename)){bool okResponse = await DisplayAlert("TextFileTryout","File " + filename +" already exists. Replace it?","Yes", "No");if (!okResponse)return;}string errorMessage = null;try{fileHelper.WriteText(filenameEntry.Text, fileEditor.Text);}catch (Exception exc){errorMessage = exc.Message;}if (errorMessage == null){filenameEntry.Text = "";fileEditor.Text = "";RefreshListView();}else{await DisplayAlert("TextFileTryout", errorMessage, "OK");}}async void OnFileListViewItemSelected(object sender, SelectedItemChangedEventArgs args){if (args.SelectedItem == null)return;string filename = (string)args.SelectedItem;string errorMessage = null;try{fileEditor.Text = fileHelper.ReadText((string)args.SelectedItem);filenameEntry.Text = filename;}catch (Exception exc){errorMessage = exc.Message;}if (errorMessage != null){await DisplayAlert("TextFileTryout", errorMessage, "OK");}}void OnDeleteMenuItemClicked(object sender, EventArgs args){string filename = (string)((MenuItem)sender).BindingContext;fileHelper.Delete(filename);RefreshListView();}void RefreshListView(){fileListView.ItemsSource = fileHelper.GetFiles();fileListView.SelectedItem = null;}
}

代码隐藏文件在三种情况下使用await运算符调用DisplayAlert:如果指定的文件名已存在,则“保存”按钮将使用DisplayAlert。这证实您的真实意图是替换现有文件。另外两个用途是用于通知保存或加载文件时发生的错误。文件保存和文件加载操作位于try和catch块中
捕捉可能发生的任何错误。例如,文件保存操作将因非法文件名而失败。在读取文件时遇到错误的可能性较小,但程序仍会检查。
可以想象,在没有await运算符的情况下可以显示通知用户错误的警报,但是他们仍然使用await来演示异常处理中涉及的基本原则:尽管C#6允许在catch块中使用await,但C#5却没有。为了解决这个限制,catch块只是将错误消息保存在名为errorMessage的变量中,然后catch块后面的代码使用DisplayAlert显示该文本(如果存在)。此结构允许这些事件处理程序根据成功完成或错误以不同的处理结束。
另请注意,构造函数以对RefreshListView的调用结束,以显示ListView中的所有现有文件,并且代码隐藏文件在保存新文件或删除文件时也调用该方法。
但是,此程序在Windows平台上不起作用。我们来解决这个问题。

第二十章:异步和文件I/O.(九)相关推荐

  1. 鸟哥的Linux私房菜(服务器)- 第二十章、WWW 伺服器

    第二十章.WWW 伺服器 最近更新日期:2011/08/05 我們最常講的『架站』其實就是架設一個 Web 網站啦!那麼什麼是 Web 呢?那就是全球資訊廣播的意思 (World Wide Web), ...

  2. 【正点原子FPGA连载】 第二十章 LCD触摸屏实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  3. 第二十章 我国农村土地管理

    农村改革解说(专著)第二十章上 第二十章 我国农村土地管理上 1.为什么进行农村土地管理? 农村土地管理,就是对农村的集体所有制的土地进行管理.它不仅包括对现有耕地的管理,而且还包括对草原.山地.林地 ...

  4. 鸟哥的Linux私房菜(基础篇)- 第二十章、启动流程、模块管理与 Loader

    第二十章.启动流程.模块管理与 Loader 最近升级日期:2009/09/14 系统启动其实是一项非常复杂的程序,因为核心得要侦测硬件并加载适当的驱动程序后,接下来则必须要呼叫程序来准备好系统运行的 ...

  5. activiti高亮显示图片_【正点原子FPGA连载】第二十章SD卡读BMP图片HDMI显示实验领航者 ZYNQ 之嵌入式开发指南...

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  6. 修改dts后重编译_「正点原子FPGA连载」第二十章另一种方式编译ZYNQ镜像

    1)摘自[正点原子]领航者 ZYNQ 之linux驱动开发指南 2)实验平台:正点原子领航者ZYNQ开发板 3)平台购买地址:https://item.taobao.com/item.htm?& ...

  7. 【正点原子Linux连载】第二十章 V4L2摄像头应用编程-摘自【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.1

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  8. 【正点原子FPGA连载】 第二十章 LCD触摸屏实验摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...

  9. 第十章、epub文件处理 -- 样式处理

    https://github.com/geometer/FBReaderJ 第十章.epub文件处理 -- 样式处理 这一章的内容比较简单,因为第九章中集中了篇幅介绍显示的流程,所以把处理样式的流程单 ...

  10. 第三集 怪物学院 第二十章

    第三集 怪物学院 第二十章 奥斯卡的大香肠和小腊肠(一) "还没完了."赵无极心中暗怒,决定给眼前这个小刺猬一点教训,右手挡在自己脸部前方,左手一掌拍向唐三胸前.当然,他这一掌并 ...

最新文章

  1. 轻松记账工程冲刺第二阶段10
  2. mac book pro怎么安装python_Mac安装python细节
  3. Quartz定时任务的基本搭建
  4. java easing_p5.js入门教程之平滑过渡(Easing)
  5. 【Android小应用】强迫症头像生成器
  6. swing禁用最大化、去掉java图标、设置窗口为中央显示
  7. python怎么输入正整数_python判断所输入的任意一个正整数是否为素数的两种方法...
  8. 一般期刊发表要求如何掌握
  9. UE4母材质之法线贴图
  10. 大数据未来七大发展方向
  11. PHP设计模式-简单工厂方法
  12. Python实现鸡群算法
  13. 微信公众号自动回复机器人
  14. ker矩阵是什么意思_深入理解旋转矩阵和平移向量的本质
  15. Java之Thread.sleep()浅析
  16. oracle 数据库基础知识复习
  17. nodejs快速上手编写程序
  18. Python提取字符串中数字(非正则提取)
  19. 新微商优品新Mac协议 微商大精灵软件
  20. vue中的横向排列_vue横向步骤条

热门文章

  1. 洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)
  2. 前端学习 第二弹: JavaScript中的一些函数与对象(1)
  3. [选择性翻译][HDP Ambari 2.2.2安装使用说明][1]
  4. 富文本常用封装(NSAttributedString浅析)
  5. WPF与输入法冲突研究之三:韩文输入法在不同平台,WinForm/WPF下的区别
  6. 苹果电脑修改hosts文件方法介绍!mac的hosts文件位置在哪?
  7. Duplicate Photos Fixer Pro for Mac用户指南:我可以比较不同时间的照片吗?
  8. 利用卷积自编码器对图片进行降噪
  9. 《Java技术》第六次作业
  10. 简单理解JavaScript中的闭包